The problem is that a member function of B
isn't a member function of A
, even if B
derives from A
. If you have a void (A::*)()
, you can invoke it on any A *
, regardless of the actual derived type of the object pointed at.
(The same principle would apply to an A &
too, of course.)
Assume B
derives from A
, and C
derives from A
; were it were possible to consider a void (B::*)()
(say) as a void (A::*)()
, one would be able to do something like this:
A *c=new C;
A *b=new B;
void (A::*f)()=&B::fn;//fn is not defined in A
(c->*f)();
And the member function of B
would be called on an object of type C
. The results would be unpredictable at best.
Based on the example code, and assuming non-use of something like boost, I'd be inclined to structure the callback as an object:
class Callback {
public:
virtual ~Callback() {
}
virtual do(int a)=0;
};
Then the function that calls the callback takes one of these objects somehow rather than a plain function pointer:
class A {
protected:
void doSomething(Callback *c) {
c->Do(1234);
}
};
You could then have one callback per derived function you are interested in calling. For doIt, for example:
class B:public A {
public:
void runDoIt() {
DoItCallback cb(this);
this->doSomething(&cb);
}
protected:
void doIt(int foo) {
// whatever
}
private:
class DoItCallback:public Callback {
public:
DoItCallback(B *b):b_(b) {}
void do(int a) {
b_->doIt(a);
}
private:
B *b_;
};
};
An obvious way of cutting back on the boilerplate would be to put the member function pointer into the callback, since the derived callback is free to deal with objects of a specific type. This would make the callback a bit more generic, in that when called back it would invoke an arbitrary member function on an object of type B:
class BCallback:public Callback {
public:
BCallback(B *obj,void (B::*fn)(int)):obj_(obj),fn_(fn) {}
void do(int a) {
(obj_->*fn_)(a);
}
private:
B *obj_;
void (B::*fn_)(int);
};
This would make doIt like this:
void B::runDoIt() {
BCallback cb(this,&B::doIt);
this->do(&cb);
}
This could potentially be "improved", though not all readers may see it quite in that way, by templating it:
template<class T>
class GenericCallback:public Callback {
public:
GenericCallback(T *obj,void (T::*fn)(int)):obj_(obj),fn_(fn) {}
void do(int a) {
(obj_->*fn_)(a);
}
private:
T *obj_;
void (T::*fn_)(int);
};
Using this, the runDoIt function above could become:
void B::runDoIt() {
GenericCallback<B> cb(this,&B::doIt);
this->do(&cb);
}
(The generic callback could also be templated on the member function pointer itself, though this is unlikely to provide any practical advantage in most cases. It's just more typing.)
I've found structuring things this way to turn out well, as it doesn't require inheritance. It therefore imposes few restrictions on the code that is to be called back, which is to my mind always a good thing, and I've found that to outweigh the verbosity that is difficult to eliminate entirely. Impossible based on the example to tell whether this approach would actually suit, though...