views:

678

answers:

4

I have a need to be able to have a super class execute callbacks defined by a class that inherits from it. I am relatively new to C++ and from what I can tell it looks like the subject of member-function-pointers is a very murky area.

I have seen answers to questions and random blog posts that discuss all sorts of things, but I am not sure if any of them are specifically dealing with my question here.

Here is a simple chunk of code that illustrates what I am trying to do. The example might not make a lot of sense, but it accurately resembles the code I am trying to write.

class A {
    protected:
    void doSomething(void (A::*someCallback)(int a)) {
        (*this.*someCallback)(1234);
    }
};

class B : public A {
    public:
    void runDoIt() { doSomething(&B::doIt); }
    void runDoSomethingElse() { doSomething(&B::doSomethingElse); }
    protected:
    void doIt(int foo) {
        cout << "Do It! [" << foo << "]\n";
    }
    void doSomethingElse(int foo) {
        cout << "Do Something Else! [" << foo << "]\n";
    }
};

int main(int argc, char *argv[]) {
    B b;
    b.runDoIt();
    b.runDoSomethingElse();
}
+6  A: 

If you can use boost libraries, I would suggest you use boost::function for the task at hand.

class A {
public:
   void doSomething( boost::function< void ( int ) > callback )
   {
      callback( 5 );
   }
};

Then any inheriting (or external class) can use boost::bind do make a call:

class B {
public:
   void my_method( int a );
};
void test()
{
   B b;
   A a;
   a.doSomething( boost::bind( &B::my_method, &b, _1 ) );
};

I have not checked the exact syntax and I have typed it from the top of my head, but that is at least close to the proper code.

David Rodríguez - dribeas
I would second this approach. Using boost here makes a lot of sense, they've dedicated a lot of effort into this sort of thing.
sstock
I was a little hesitant to use boost for anything, but I'm going to give it a try. It works more or less as you've described here!
Beau Simensen
A: 

You trying to call method which defined in derived class as method base class.
But this function is not defined in base class.

bb
+2  A: 

C++ provides better constructs than member function pointers for your purpose. (Generally speaking, you shouldn't have to use function pointers in properly written pure C++). Two options off the top of my head:

1) Create a pure virtual function on A called doIt(). Call doIt() from doSomething(). On B, keep an enum member variable to indicate what you want to do, and set it before you call doSomething(). Override doIt() in B, with its implementation switch/casing the member enum to the underlying code you wish to run.

2) Create a DoInterface class with a single doIt() pure virtual method. Create derivatives of this for your Class B which have a pointer to the owning B instance and implement doIt() calling the appropriate function on B in each of your DoInterface implementations. doSomething() would take an instance of a DoInterface as a parameter. This is called a callback-object pattern.

Not Sure
Option 1, virtual member functions, is almost always the easiest and most elegant way to do this, with one caveat: virtual members cannot be called from base class constructors or destructors. But as long as you don't need to do that, that's the way to go.
Tyler McHenry
If I only had to worry about one method, or knew exactly how many methods I would want to "do", this would work. I'll look into it more closely but I don't think this will work for my purposes as I was already pretty much doing this.
Beau Simensen
That's the point of B being a derivative class of A. B knows exactly how many methods it has that can be "done" and knows when which ones should be done, it just requires a trigger from A, which is the point of the overridden doIt() on B.
Not Sure
+3  A: 

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...

brone
I'm going to try doing it this way. It will be more verbose than I was hoping for, but I think it will be better than the next best solution which involved casing and switching.
Beau Simensen
Very nice answer for learning. The approach you give is close to a limited version of boost libs. The callback is a limited version of boost::function and the GenericCallback is a reduced version of bind.
David Rodríguez - dribeas
David Rodríguez - dribeas
Very interesting answer, I learned something. Thanks brone.
sstock
This was an awesome answer. But I think I might be going with boost this time around. Will definitely refer to this, though, as I might prefer a solution like this for other projects in the future!
Beau Simensen