views:

1298

answers:

3

Suppose I have some code like this:

class Visitor {
   public:
      Visitor(callBackFunction) {}
      void visit() {
          //do something useful
          invokeCallback();
      }
}

class ClassThatCanBeVisited {
    Visitor &visitor;

    public:
       ClassThatCanBeVisited(Visitor &_visitor) : visitor(_visitor){}
       void someUsefulMethod() {
          int data= 42;
          visitor.visit(data);
       }
};


void callBackFunction() {
    //do something useful in the context of the Main file
}
int main() {
     Visitor visitor;
     ClassThatCanBeVisited foo(visitor);
     foo.someUsefulMethod();
}

I need to create a simple callback that will be called whenever the Visitor::visit() is called. I know that I probably should put the code of the callback inside my Visitor, but it is in a different context, so I would like to pass the callBackFunction() to the Visitor so he could invoke my callback function.

I looked for things on the web and saw boost::function, but c++ already has the basic functors.

Which one should I use for better clarity of the code? The callback is going to be a simple void() function, but it might grow, you never know the future :)

What is the recommended way to do this?

+4  A: 

Yes boost::function would do this well. That's a very common usage of it. You will need to use boost::bind to bind the instance to the member function.

 func = boost::bind( &MyClass::CallbackFunc, this);

Would be how you would do that from within the class.

Be sure the "this" doesn't dissapear or your boost function will crash in the middle of some boost header somewhere.

Doug T.
Have "this" implement the boost::shared_from_this, and store a weak pointer in your bind?
Matt Cruikshank
+2  A: 

You can use callback interface and its hierarchy if you don't want to use boost::function.

class VisitorCallback
{
public:
    virtual void handle( const Visitor& ) = 0;
};

If you have or can use boost::function - use it, it is a good way to get rid of all those callback classes.

Edit:
@edisongustavo:

boost::function and boost::bind won't probably make your code more readable. But it will give you an opportunity to pass free functions ( I mean functions out of class and static class functions ) as callback as well as existing functions of any class.

With boost functions you can pass functions with for example 2 parameters as callback which expect only one parameter.

typedef boost::function< void ( int ) > IntExpectingCallback;

void TwoIntFunction( int, int );
{
}
...
IntExpectingCallback callback = boost::bind( TwoIntFunction, 5, _1 );

But again, this won't make your code more readable unless all your team knows and favor boost.

Mykola Golubyev
This is the usual way I'm used to doing things (since I come from Java), but I don't see these callbacks as a good thing (too many classes, everybody saying boost::function is better, etc.)So in which way would boost::bind make my code more readable?
Edison Gustavo Muenz
boost::function frees you from having to inherit from a base class just to have a callback.It also frees you from being limited by the function name.In essence, it can be used to decrease coupling.
Trey Jackson
+1 on the boost::function part, but I do not like the var_args approach. It is limited in different ways: you loose type safety, caller and callee must agree on an end-of-argument-list token and not every class can be passed through ellipsis (only PODs if I recall correctly)
David Rodríguez - dribeas
@dribeas: I didn't mean ellipsis by "...". My fault. I just meant your parameters. Changed.
Mykola Golubyev
+1  A: 

The above answers are great, but I'd just like to point out something you mentioned in your question, which is still relevant to your choice between C++ callback objects (in Mykola's answer) and boost.

"the callback is going to be a simple void() function, but it might grow, you never know the future :)"

This is probably the worst reason to extra, unnecessary functionality - that is "just in case you need it". If you don't know - then don't do more than is necessary, chances are your guess will be wrong anyway, especially by the time you need it.

On the other hand, if you do know that it is extremely likely you will need the functionality very soon, then it might be worth adding it.

Again to re-iterate what Mykola said - if you already have boost in your project and your team likes it, then use that, but otherwise it may be overkill.

Justicle
I agree with that approach. It is one more reason I used boost::function. It is simple, decouples the implementation, and so on. Creating a whole new class to have a simple void() function seemed overkill for that problem, but I didn't want a function pointer. So the boost::function worked pretty well.And I actually had to increase the params of the function, so it helped me twice
Edison Gustavo Muenz