Pointer to function in class variable

Is it possible to save a pointer to a class method in a variable of this or another class? If this is not possible, I would also like to know why.

It is possible to create a variable outside the class, and assign a class method to it. Also call this method. But with the inclusion of this variable as a class field, the example stops working.

It is also possible to call this method in the class itself with the this pointer. Why does this work like that?

Not working example. Desired result

#include <iostream>

using namespace std;


class B {
public:
    typedef void (B::*function_type)(void);
    B::function_type _func;

    B() {
        cout << "B" << endl;
    }
    void foo(){
        cout << "B foo" << endl;
    }
};

int main()
{
    B b;
    b._func = &B::foo;

    (b.*_func)();
}

Call inside class working

#include <iostream>
#include <functional>

using namespace std;


class B {
public:
    typedef void (B::*function_type)(void);
    B::function_type _func;

    B() {
        cout << "B" << endl;
    }
    void foo(){
        cout << "B foo" << endl;
    }

    void run() {
        (this->*_func)();
    }
};

int main()
{
    B b;
    b._func = &B::foo;
    b.run();
}

I would like to save a class method and call it through an object.

Upvotes: 0

Views: 99

Answers (3)

Landstalker
Landstalker

Reputation: 1368

Your first example (the one that does not work) can work only if you are referring to a static function because the static methods can be called without a calling object instance that corresponds in your case to (b.*(b._func))();

So, you can write :

class B {

public:
    typedef void (*function_type)(void);
    function_type _func;

    B() { cout << "B" << endl;}
    static void foo(){ cout << "B foo" << endl; }
};

int main()
{
    B b;
    b._func = &B::foo;
    (b._func) ();
}

Upvotes: 0

Pete Becker
Pete Becker

Reputation: 76498

There are two objects involved in calling your _func pointer. One is the object that the function should be applied to, and one is the object that holds the pointer. When you're inside a member function, the first one is implied; it's the internal this pointer. So (this->*_func)() calls the data member _func on the current object. When you're outside a member function you have to supply both objects:

(b.*b._func)();

The b on the left is like the this-> in the first version: it tells the compiler what object to apply the function too. The second b is the object that holds the pointer.

If that's thoroughly confusing, change the situation a bit. Use two B objects and play with which one is which:

B b;
B b1;

(b.*b1.func)();
(b1.*b.func)();

Upvotes: 3

bolov
bolov

Reputation: 75874

It is possible. The syntax is a little bit scary though:

(b.*(b._func))();

Why is it like that? Well, first you need to refer to the data member _func of object b. That is b._func. Next you need to call that data member as a data function pointer which is the (b.*(..))() part.

I would suggest to simplify the calling side by creating a method that does the crazy call syntax stuff:

class B {
    // ...
    void call_me()
    {
        (this->*(_func))();
    }

};

b.call_me();

Some tips to improve:

Use using instead of typedef:

using function_type = void (B::*)(void);

And you don't need B::function_type. Just function_type is enough because you are inside the scope of the class.

Upvotes: 1

Related Questions