![]() |
|
Member Function Pointers and Inheritance |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
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??? 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. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
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. |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
There's no magical cast I can use??? EDIT My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Polybios
Member #12,293
October 2010
|
Maybe something like that: 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. Edit2: |
bamccaig
Member #7,536
July 2006
![]() |
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. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
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 think this is a possibility. If the function weren't virtual then it would call the correct version. EDIT 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
My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
|