Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Member Function Pointers and Inheritance

This thread is locked; no one can reply to it. rss feed Print
Member Function Pointers and Inheritance
Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Howdy.

I've got some code I want to simplify (complicate) by using member function pointers.

I've got a set of flag state setter functions in my WidgetBase base class. Their type is void (WidgetBase::*StateSetter)(bool). My question is this : They are declared as virtual in the WidgetBase base class, and they are overridden in derived classes as necessary. Now suppose I have a derived class that is overloading one of these state setter functions, but needs to call the base class implementation of the function. How do I do that with member function pointers? Is it enough to declare their type as void (WidgetBase::*StateSetter)(bool)? Will that call the base class function if I call it on an object of derived type because it is declared to be a member function of class WidgetBase? Or will it call a derived class implementation because it is a virtual function?

Code example :

class WidgetBase {
   /// ...
   virtual void SetEnabledState      (bool state);// Sets bg redraw flag
   virtual void SetVisibilityState   (bool state);// Sets bg redraw flag
   virtual void SetHoverState        (bool state);// /* Does not set any redraw flag */ - OLD:Sets redraw flag and (false) sets bg redraw flag
   virtual void SetFocusState        (bool state);// Sets redraw flag and (false) sets bg redraw flag
   virtual void SetMoveableState     (bool state);// Does not set redraw flag
   virtual void SetResizeableState   (bool state);// Does not set redraw flag
   virtual void SetNeedsRedrawState  (bool state);
   virtual void SetNeedsBgRedrawState(bool state);// (true) sets redraw flag
   virtual void SetAllowCloseState   (bool state);// Does not set redraw flag
   virtual void SetAllowOverlapState (bool state);// Does not set redraw flag
};

And then in the derived class (in this case, a TextDecorator, which inherits publically from Decorator, which inherits publically from WidgetBase) I want to call this member function on three different objects, 1) A BasicButton* (derived from WidgetBase), 2) A Layout* (also derived from WidgetBase) and 3) the Decorator base of a TextDecorator object).

So I have code like this :

void TextDecorator::SetFlagState(bool state , void (WidgetBase::*StateSetter)(bool)) {
   if (basic_text_widget) {
      (basic_text_widget.*StateSetter)(state);
   }
   (text_widget_layout->*StateSetter)(state);
   (this->*StateSetter)(state);
}

And then in my overloaded TextDecorator state setter functions I want to call it like this :

void TextDecorator::SetEnabledState(bool state) {
   SetFlagState(state , WidgetBase::SetEnabledState);
}

void TextDecorator::SetVisibilityState(bool state) {
   SetFlagState(state , WidgetBase::SetVisibilityState);
}

/// so on... etc...

Will this call the base class state setter or the virtual one? Is this compiler dependent? I am running a little test on some example classes. It seems that virtual inheritance is used and it calls the derived class function instead of the base class one. Is it possible to make it call the base class function instead???

#SelectExpand
1 2 3#include <iostream> 4using std::cout; 5using std::endl; 6#include <cstdlib> 7 8 9class A { 10public : 11 virtual void DoThis() {cout << "A::DoThis" << endl;} 12}; 13 14class B : public A { 15public : 16 virtual void DoThis() {cout << "B::DoThis" << endl;} 17}; 18 19class C : public B { 20public : 21 virtual void DoThis() {cout << "C::DoThis" << endl;} 22}; 23 24void DoStuff(A* a , void (A::*DoStuffFunction)()) { 25 (a->*DoStuffFunction)(); 26 return; 27} 28 29 30 31 32 33int main(int argc , char** argv) { 34 35 A a; 36 B b; 37 C c; 38 39 DoStuff(&a , &A::DoThis); 40 DoStuff(&b , &A::DoThis); 41 DoStuff(&c , &A::DoThis); 42 DoStuff(dynamic_cast<A*>(&a) , &A::DoThis); 43 DoStuff(dynamic_cast<A*>(&b) , &A::DoThis); 44 DoStuff(dynamic_cast<A*>(&c) , &A::DoThis); 45 DoStuff(static_cast<A*>(&a) , &A::DoThis); 46 DoStuff(static_cast<A*>(&b) , &A::DoThis); 47 DoStuff(static_cast<A*>(&c) , &A::DoThis); 48/// DoStuff(&b , &B::DoThis);/// Error 49/// DoStuff(&c , &C::DoThis);/// Error 50 51 system("Pause"); 52 53 return 0; 54}

The output from the program is :

c:\ctwoplus\progcode\test\MemberFunctionPointers>mfp.exe
A::DoThis
B::DoThis
C::DoThis
A::DoThis
B::DoThis
C::DoThis
A::DoThis
B::DoThis
C::DoThis
Press any key to continue . . .

I'm using this to condense code and reuse it. Unless you have a better option, or you know what I could do instead to produce clean concise code, please keep your suggestions limited to how I can make this work. No macros please.

Polybios
Member #12,293
October 2010

As I've understood it, it's not possible, as pointer to member functions will always call the "correct" virtual function. Maybe think of them as pointing to some fixed vtable-index. You could write a non virtual helper or use a lambda with std::function.
I wouldn't use raw pointers to member functions at all, but strongly favor std::function for storage. It has a small overhead though (it uses the heap to store bound data).

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Polybios
Member #12,293
October 2010

Maybe something like that:

#SelectExpand
1... 2 3void DoStuff(A* a , std::function<void(A* a)> &&do_stuff) { 4// (a->A::*DoStuffFunction)(); 5 do_stuff(a); 6 return; 7} 8 9 10int main(int argc , char** argv) { 11 12 A a; 13 B b; 14 C c; 15 16 DoStuff(&a, [](A*a){ a->A::DoThis(); }); 17 DoStuff(&b, [](A*a){ a->A::DoThis(); }); 18 DoStuff(&c, [](A*a){ a->A::DoThis(); }); 19}

Edit: You can save the lambda, of course, and probably shouldn't move (no &&)... It's past midnight now here ^^ But you'll get the idea I guess.
I'm not sure whether it's a good idea to work "against" polymorphism.
The lambda is actually a plain old function in this case, as nothing is captured.
So you could also pass by plain-old function pointer instead of std::function, as it will decay to a function pointer when you don't capture anything. Going to bed now.

Edit2:
I'd probably design it differently: Have the flag manipulation going on in the base class exclusively, being non-virtual, then let those functions call virtual methods like "visibilityChanged()" which can be overriden to react to state changes. Not sure whether that is something you want, though. Now definitively going to bed.

bamccaig
Member #7,536
July 2006
avatar

Typically overridden derived methods don't implicitly call their base methods. It's up to you to decide if that's desirable (sometimes it isn't). In C++, due to multiple inheritance, you invoke the base by name, IIRC... Should be something like this:

this->BaseClass::method_name(args);

As usual, this-> will be optional (but I think it's a feature, not a bug).

It's late, but it looks like your use of function pointers here is merely for code reuse (which should be reasonable). You'd want your method to call the base class method (that's the usual pattern). It shouldn't be affected...

If you're using function pointers for more than that then you might consider C++ features over C features. Function pointers are sort of a C-feature that are just inherited into C++. I don't imagine that they're encouraged.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

bamccaig said:

Typically overridden derived methods don't implicitly call their base methods. It's up to you to decide if that's desirable (sometimes it isn't). In C++, due to multiple inheritance, you invoke the base by name, IIRC... Should be something like this:

this->BaseClass::method_name(args);

The overridden methods need to call the base class methods because they are the ones that actually set the state. That's why they're provided. I was looking for that syntax, but in this case it doesn't help because I'm calling the function through a pointer. The variable is the member function. I could write out the calls all by hand but then I can't use a single function call for all the functions that use it. That's why I was using a member function pointer, because the function to call is what varies.

bamccaig said:

It's late, but it looks like your use of function pointers here is merely for code reuse (which should be reasonable). You'd want your method to call the base class method (that's the usual pattern). It shouldn't be affected...

That's just it, I can't call the base class through the function pointer because it calls the virtual method.

I find it hard to believe that C++ would make such a giant oversight as not allowing for a function pointer to point to a certain member function, virtual or not. There must be a way.

Is there any way to write the following function so that it will compile?

void TextDecorator::SetFlagState(bool state , void (WidgetBase::*StateSetter)(bool)) {
   if (basic_text_widget) {
      (basic_text_widget->WidgetBase::*StateSetter)(state);
   }
   (text_widget_layout->WidgetBase::*StateSetter)(state);
   (this->WidgetDecoratorBase::*StateSetter)(state);
}

What I need it to do is call the state setter of the basic text widget from it's base class WidgetBase. Same for the text widget layout. Then for this I need it to call the state setter from the WidgetDecoratorBase class. Is any of this possible with C++?

PolyBios said:

Edit2:
I'd probably design it differently: Have the flag manipulation going on in the base class exclusively, being non-virtual, then let those functions call virtual methods like "visibilityChanged()" which can be overriden to react to state changes. Not sure whether that is something you want, though. Now definitively going to bed.

I think this is a possibility. If the function weren't virtual then it would call the correct version.

EDIT
It turns out this is partly possible. If I cast to a WidgetBase before calling the member function pointer then it will call the base class function. The problem is that this makes a temporary copy of the object, and doesn't actually affect the object directly any more.

Base b;
Derived d;
void (Base::*)() bfunc = Base::func;
d.*bfunc();// No good, calls D::func
Base bd(d);// Have to make a base class copy
(bd.*bfunc)();// Will call the base class Base::func
// not helpful

Go to: