C++ Memberfunction-pointers in inheritance

Started by
6 comments, last by SiCrane 13 years, 11 months ago
Hey guys this is my first question to this forum and it is a hard one for me. I want to implement some function pointers. Here is the class structure:

class A{
  virtual void function()=0;
public:
  void (A::*func_ptr)();
};

class B:public A{
  virtual void function();
public:
  B();
};
//Several other classes that inherit A and will override function()

B::B()
:func_ptr(&B::function)
{}

The problem is that the compiler says:

cannot convert 'void (B::*)()' to 'void (A::*)()' in assignment
So I can not initialize the member func_ptr of B with this functionpointer. Is there any possible way to manage this? I guess forcing a cast could result in major problems as memberfunctions are treated differently. I want to use this pointers rather than inheritance overriding because of the overhead. It is used in a very high performance code. I hope there is someone out there who can solve my problem. Thanks for reading, I am looking forward for your answers.
Advertisement
The C++ language does not support contravariance. You can not do what you are trying to do. My experience is that if the language does not support you trying to do something wacky, it's your design that's broken not the language.

Can you post your performance analysis numbers showing that dereferencing pointers to member functions is faster than using virtual functions? I would be very interested in seeing this.

Stephen M. Webb
Professional Free Software Developer

Quote:Original post by Spynacker
I want to use this pointers rather than inheritance overriding because of
the overhead. It is used in a very high performance code.


If it's "high performance" code, then polymorphism is the wrong choice anyway.

If complete support of polymorphic types is required, then there is boost::function.

Quote:
B::B():func_ptr(&B::function)

If function is polymorphic, then func_ptr(&A::function) does exactly the same thing.
I didn't know inheritance had such a performance impact...

I guess you could either perform a static_cast (but there is much likely some undefined behaviour here...), or use templates:

template <class T>class A{public:    A(T *i_ptr, void (T::*i_func_ptr)());    virtual void function() = 0;private:    T *m_ptr;    void (T::*m_func_ptr)();};class B: public A<B>{public:    B();    void function();};template <class T>A<T>::A(T *i_ptr, void (T::*i_func_ptr)()) :    m_ptr(i_ptr),    m_func_ptr(i_func_ptr){    (m_ptr->*m_func_ptr)(); // crash: pure virtual method called}B::B() :    A<B>(this, &B::function){}void B::function(){    std::cout << "function invoked\n";}


I have no idea why this crashes, I guess you should even be able to get away with not passing the 'this' pointer...it's not working but it gives you a clue (maybe someone else knows what is wrong?).

Also, if this is only to avoid inheritance...is that even worth it?
[size="2"]SignatureShuffle: [size="2"]Random signature images on fora
Quote:
I have no idea why this crashes, I guess you should even be able to get away with not passing the 'this' pointer...it's not working but it gives you a clue (maybe someone else knows what is wrong?).

You are calling a virtual function of an imcompletely constructed object.

Quote:
I didn't know inheritance had such a performance impact...

It depends on what you are doing and how you are measuring. Typically, inheritance is free - but virtual functions incur a small overhead for dynamic dispatch.

Ideally the amount of work done in the method would easily amortise the cost of the virtual function. If not, this might hint that your design needs work.

@Spynacker: can you give us a high level overview of what you are doing? High performance is typically achieved with macro optimisations first, only later moving down to micro optimisations if the performance criteria have not been met.
Quote:Original post by rip-off
You are calling a virtual function of an imcompletely constructed object.


Heh yeah, now I see it too...lame ^_^

Quote:
It depends on what you are doing and how you are measuring. Typically, inheritance is free - but virtual functions incur a small overhead for dynamic dispatch.


True, but the cost of dynamic dispatching is really really low. And I think it greatly out weights the advantages over the tiny bit of real time cost (unless you really have a vast amount of virtual functions..).

[size="2"]SignatureShuffle: [size="2"]Random signature images on fora
Thanks for the posts so far folks.
To make things a bit more clear let me explain some
more details.
I have about 10 different subclasses of A that all will
implement their own version of function. There will be a
lot of instances of all these subclasses that are handled
as objects of A in a std::list<A*>. All of these hundreds of
instances will get called with function() thousands of times
so every little bit of performance increase will help.

To answer some of your statements:
This "high-performance code" should not be written in low-level design.
I brought it to live in a very beautiful class design and then began to
increase performance by adding assemblerparts and restructuring the code.
Now I am at the point that my structure itself prevents further increase
if I let the class structure be.
For the sake of beeing able to easily expand my project I do not want to
tear the classes down but I need some change in there.

Maybe I will look for Boost but for now I am considering to reject the
subclasses of A and put every special function into a. That would be an
awful step back but with my eyes looking forward to further actions this
could be the best solution.

I would appriciate other opinions and advices.
Be very careful before you decide to place additional data members in a class to speed up a computation. It's entirely possible that additional data member will actually slow down the computation by increasing class size and thus giving you worse cache coherency. I've done an informal study comparing dispatch methods for classes, and it's really hard to beat normal virtual functions in the normal case where you want to do something different for each derived class.

This topic is closed to new replies.

Advertisement