How do I implement a callback in C++?

前端 未结 6 2209
野性不改
野性不改 2020-12-05 19:52

I want to implement a class in c++ that has a callback.

So I think I need a method that has 2 arguments:

  • the target object. (let\'s say *myObj)
  • <
相关标签:
6条回答
  • 2020-12-05 20:09

    Also, look at the Observer Pattern and signals and slots . This extends to multiple subscribers.

    0 讨论(0)
  • 2020-12-05 20:10

    The Observer design pattern seems to be what you're looking for.

    0 讨论(0)
  • 2020-12-05 20:14

    One trick is to use interfaces instead, that way you don't need specifically to know the class in your 'MyClassWithCallback', if the object passed in implements the interface.

    e.g. (pseudo code)

    struct myinterface
    {
      void doSomething()=0;
    };
    
    class Target : public myinterface { ..implement doSomething... };
    

    and

    myinterface *targetObj; 
    void setCallback(myinterface *myObj){
        targetObj = myObj;
    };
    

    doing the callback

    targetObj->doSomething();
    

    setting it up:

    Target myTarget;
    MyClassWithCallback myCaller;
    myCaller.setCallback(myTarget);
    
    0 讨论(0)
  • 2020-12-05 20:19

    The best solution, use boost::function with boost::bind, or if your compiler supports tr1/c++0x use std::tr1::function and std::tr1::bind.

    So it becomes as simple as:

    boost::function<void()> callback;
    Target myTarget;
    callback=boost::bind(&Target::doSomething,&myTarget);
    
    callback(); // calls the function
    

    And your set callback becomes:

    class MyClassWithCallback{
    public:
      void setCallback(boost::function<void()> const &cb)
      {
         callback_ = cb;
      }
      void call_it() { callback_(); }
    private:
      boost::function<void()> callback_;
    };
    

    Otherwise you need to implement some abstract class

    struct callback { 
     virtual void call() = 0;
     virtual ~callback() {}
    };
    
    struct TargetCallback {
     virtual void call() { ((*self).*member)()); }
     void (Target::*member)();
     Target *self;
     TargetCallback(void (Target::*m)(),Target *p) : 
           member(m),
           self(p)
     {}
    };
    

    And then use:

    myCaller.setCallback(new TargetCallback(&Target::doSomething,&myTarget));
    

    When your class get modified into:

    class MyClassWithCallback{
    public:
      void setCallback(callback *cb)
      {
         callback_.reset(cb);
      }
      void call_it() { callback_->call(); }
    private:
      std::auto_ptr<callback> callback_;
    };
    

    And of course if the function you want to call does not change you may just implement some interface, i.e. derive Target from some abstract class with this call.

    0 讨论(0)
  • 2020-12-05 20:20

    You have a few basic options:

    1) Specify what class the callback is going to use, so that the object pointer and member function pointer types are known, and can be used in the caller. The class might have several member functions with the same signature, which you can choose between, but your options are quite limited.

    One thing that you've done wrong in your code is that member function pointers and free function pointers in C++ are not the same, and are not compatible types. Your callback registration function takes a function pointer, but you're trying to pass it a member function pointer. Not allowed. Furthermore, the type of the "this" object is part of the type of a member function pointer, so there's no such thing in C++ as "a pointer to any member function which takes an integer and returns void". It has to be, "a pointer to any member function of Target which takes an integer and returns void". Hence the limited options.

    2) Define a pure virtual function in an interface class. Any class which wants to receive the callback therefore can inherit from the interface class. Thanks to multiple inheritance, this doesn't interfere with the rest of your class hierarchy. This is almost exactly the same as defining an Interface in Java.

    3) Use a non-member function for the callback. The for each class which wants to use it, you write a little stub free function which takes the object pointer and calls the right member function on it. So in your case you'd have:

    dosomething_stub(void *obj, int a) {
        ((Target *)obj)->doSomething(a);
    }
    

    4) Use templates:

    template<typename CB> class MyClassWithCallback {
        CB *callback;
     public:
        void setCallback(CB &cb) { callback = &cb; }
        void callCallback(int a) {
            callback(a);
        }
    };
    
    class Target {
        void operator()(int a) { /* do something; */ }
    };
    
    int main() {
        Target t;
        MyClassWithCallback<T> caller;
        caller.setCallback(t);
    }
    

    Whether you can use templates depends whether your ClassWithCallback is part of some big old framework - if so then it might not be possible (to be precise: might require some more tricks, such as a template class which inherits from a non-template class having a virtual member function), because you can't necessarily instantiate the entire framework once for each callback recipient.

    0 讨论(0)
  • 2020-12-05 20:20

    In C++, pointers to class methods are hardly used. The fact that you called in - it is delegates and their use is not recommended. Instead of them, you must use virtual functions and abstract classes. However, C++ would not have been so fond of me, if it not supported completely different concepts of programming. If you still want delegates, you should look towards "boost functional" (part of C + +0 x), it allows pointers to methods of classes regardless of the class name. Besides, in C++ Builder has type __closure - implementation of a delegate at the level of the compiler.

    P.S. Sorry for bad English...

    0 讨论(0)
提交回复
热议问题