John Humphreys
John Humphreys

Reputation: 39274

Member function pointer to unspecified class type - is it possible?

Is it possible to declare a function pointer (non C++ 11) that can point to a member function of any class (read: not a specific class)?

For example, if I had class A, B, and C. C has a function pointer declared in it, and I'd like to switch that pointer between pointing to one of B's member function's and one of A's member functions. Does C++ allow this?

Upvotes: 5

Views: 1784

Answers (5)

Jens Åkerblom
Jens Åkerblom

Reputation: 908

Yes you can, but you have to remove some type safety and keep track of the this pointer as well as the member function.

You can see a use-case in http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates. The basic idea is to store the object pointer as a void pointer and redirect the function call through a static method.

#include <iostream>
using namespace std;

struct A { void foo() { cout << "A::foo\n"; } };
struct B { void foo() { cout << "B::foo\n"; } };

class C
{
public:
    C() : object_ptr(0), stub_ptr(0) {}

    template <class T, void (T::*TMethod)()>
    static C from_method(T* object_ptr)
    {
        C d;
        d.object_ptr = object_ptr;
        d.stub_ptr = &method_stub<T, TMethod>;
        return d;
    }

    void operator()() const
    {
        return (*stub_ptr)(object_ptr);
    }

private:
    typedef void (*stub_type)(void* object_ptr);

    void* object_ptr;
    stub_type stub_ptr;

    template <class T, void (T::*TMethod)()>
    static void method_stub(void* object_ptr)
    {
        T* p = static_cast<T*>(object_ptr);
        return (p->*TMethod)();
    }
};

int main() 
{
    A a;
    B b;

    C c = C::from_method<A, &A::foo>(&a);

    c();

    c = C::from_method<B, &B::foo>(&b);

    c();

    return 0;
}

The code above should print

A::foo
B::foo

This solution is faster than using std::function since it doesn't require a heap allocated storage for the data but this may only be used to reference member functions (unlike std::function that claims ownership of any callable object).

Upvotes: 5

Xeo
Xeo

Reputation: 131789

boost::function is able to do this together with boost::bind:

#incluce <boost/function.hpp>
#include <boost/bind.hpp>

struct A{ void f(); };
struct B{ void g(); };
struct C{
  boost::function<void()> _func;
};

int main(){
  A a; B b; C c;
  c.func = boost::bind(&A::f, &a);
  c.func();
  c.func = boost::bind(&B::g, &b);
  c.func();
}

Upvotes: 3

PlasmaHH
PlasmaHH

Reputation: 16046

No, you can't.

And it would not make sense if you could. Imagine for a moment that you could, and you have an object of type A and call a member function pointer that points to a member function of type B. Suddenly in a member function of B you would have a this pointer, pointing to the address of an A object, but having the type B*.

It depends on what the real problem is that you are trying to solve (maybe you should have asked about that) but you can try letting all classes have a common base function (maybe virtual) and use pointers to those, but unless you provide us with more detail, we could only guess.

Another, more broad, alternative could be to use boost::function objects, that are already tied to the object you want to call your member function on.

Upvotes: 0

Paul Manta
Paul Manta

Reputation: 31567

It's not possible. When you declare a member function of a class, that function has an implicit this parameter, so even though you write void A::func(int i), the function actually has this signature:

void func(A *const this, int i)

You're going to need somethign like Boost.Function and Boost.Bind used together to do what you want to achieve:

boost::function<void (int)> func;
A* a = new A;
func = boost::bind(&A::func, a, _1);

Upvotes: 1

kennytm
kennytm

Reputation: 523224

No, but you could make A and B have a common base class X, and then you could use T (X::*)(U...) for both A and B (assuming the T and U are the same).

Or you could simply use boost::variant.

Upvotes: 0

Related Questions