Reputation: 39274
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
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
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
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
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
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