Advertisement

Pointers to class member functions

Started by July 08, 2000 03:40 AM
4 comments, last by IO Fission 24 years, 5 months ago
Is there a way to create, say, an array of pointers to a bunch of functions located in a class? I''ve tried it before but couldn''t get passed the error messages, so I just made them global functions. Any ideas? __________________________ "I like the green one better."
There are two ways to do that. Use the first if you don't need access to a particular object:

1) Use static member functions instead of global functions. Pointers to static member functions work just like regular function pointers, but you can't access non-static members from a static member function.

                                                                class Test{public:    static void Function1();    static void Function2();}; static void Test::Function1() { ... }static void Test::Function2() { ... } typedef void (*TestFuncPtr)(); int main(){    TestFuncPtr funcs[] =     {        &Test::Function1,        &Test::Function2    };     (*funcs[0])();    (*funcs[1])();     return 0;}        


(Argh! I can't get more than one source block to work on this board. I'll split this into separate posts...)

Edited by - EvilTwin on July 8, 2000 2:57:24 PM
Advertisement
(continued...)

2) Use pointers to non-static member functions. You must supply an object when you call a function through a non-static member function pointer, but you''ll have full access to the class members for that object. (You need to be careful with these, because unlike other pointers, pointers to non-static member functions aren''t actually addresses, and they may even be 64 bits if you''re using gcc or multiple inheritance in VC++. Of course, even virtual non-static member functions have 32-bit addresses just like any other function, and those addresses are stored in the virtual function tables for your classes, but the pointers don''t contain specific addresses because you may invoke them with objects that override the function you''re trying to call. To support dynamic dispatch of virtual functions correctly, pointers to non-static member functions contain information on how to call the correct function for a given object rather than the address of the specific implementation that you specify. They work fine, just don''t try to cast them to anything else.)

    class Test{public:    void Function1();    void Function2();}; void Function1() { ... };void Function2() { ... }; typedef void (Test::*TestMemberFuncPtr)(); int main(){    Test t;    Test* pt = &t    TestMemberFuncPtr funcs[] =     {        &Test::Function1,        &Test::Function2    };     (t.*funcs[0])();    (pt->*funcs[1])();     return 0;}    
(continued...)

Again, in most situations, the first approach is better. There''s is a third option, which is sort of a more object-oriented version of the first. (This approach was suggested by null_pointer in a similar thread last week.)

3) Use small classes to encapsulate your functions, where each class implements one function, and all inherit from an abstract base class. Your function table would contain pointers to the abstract base class and the functions themselves would be called through dynamic dispatch.

    class Test{    // ...}; class TestFunction{public:    virtual void Call() = 0;}; class TestFunctionFoo : public TestFunction{public:    virtual void Call();}; void TestFunctionFoo::Call() {     // Foo function} class TestFunctionBar : public TestFunction{public:    virtual void Call();}; void TestFunctionBar::Call() {     // Bar function} int main(){    TestFunction* funcs[] =     {        new TestFunctionFoo,        new TestFunctionBar    };     funcs[0]->Call(); // call Foo    funcs[1]->Call(); // call Bar     delete funcs[0];    delete funcs[1];    return 0;}    
The third method is also the slowest, the way it probably should be done on a non-time critical path. #2 is a good compromise, though very clurgy. When have you ever seen ->* used in someone else code? #1 is bad programing style, though is the eastiest (and the way I do it)

Perhaps the methodology of #2 could be internal to the class. Make it a statemachine; add a few bonus functions to set the behavior, and then call a generic execute function

        class FooXL;typedef void (FooXL::*MethodPtr)();class FooXL{public:FooXL();~FooXL();inline void DoYourThing(long);protected:MethodPtr* Functions;void Option1();void Option2();};FooXL::FooXL(){Functions = new MethodPtr[2];Functions[0] = &Option1Functions[1] = &Option2}FooXL::~FooXL{delete[] Functions;}void FooXL::DoYourThing(long i){*(MethodPtr<i>)();}        


*edit* Is there a special tag for C++ code? *edit*

-Magmai Kai Holmlor

I am brazen and fear no flames.
(So long as I don't lose this Ring of Fire Protection +5)


Edited by - Magmai Kai Holmlor on July 8, 2000 3:46:36 PM
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Ok, thanx for all that, but it feels a bit too far over my head for me (like a couple of thousand feet above...) I''ve got it pretty good just having them global and in seperate .cpp and .h files. I think I''ll leave it like that. One thing, though. What if I put them into a namespace? Would that cause the same/similar problems?


__________________________
"I like the green one better."

This topic is closed to new replies.

Advertisement