How to pass a method as callback to another class?

2019-03-06 12:36发布

I have a question regarding callbacks using tr1::function. I've defined the following:

  class SomeClass {
    public:
      typedef std::tr1::function<void(unsigned char*, int)> Callback;
      void registerCallback(Callback);
    private:
      Callback callback;
  }

I've defined another class:

  class SomeOtherClass {
      void myCallback(unsigned char*, int);

  }

Now I want to register my function 'myCallback' as callback at class 'SomeClass'using the method 'registerCallback'. However, it is not working. I've had a look on the boost documentation on the function and it seems legit to use (member) methods of a class for callbacks. Am I wrong?

Thanks in advance!

标签: c++ callback
4条回答
唯我独甜
2楼-- · 2019-03-06 12:44

Use templates:

template <class T>
class B
{
  public:
    typedef void (T::*TCallBackFunction)(void);   
    void SetCallBack(T* pCallBackClass, TCallBackFunction pCallBackFunction)
    {
      if(pCallBackFunction && pCallBackClass)
      {
        m_pCallBackFunction = pCallBackFunction;
        m_pCallBackClass = pCallBackClass;
      }
    }
    void StartCallBackFunction()
    {
      (pCallBackClass->(*m_pCallBackFunction))();
    }
  private:
    TCallBackFunction m_pCallBackFunction;
    T* m_pCallBackClass;
};

Such like this. And use it:

...
B<MyClass> b;
b.SetCallBack(&b, &MyClass::MyFunction);
...
查看更多
再贱就再见
3楼-- · 2019-03-06 12:53

Member functions have an implicit first parameter, a this pointer so as to know which object to call the function on. Normally, it's hidden from you, but to bind a member function to std::function, you need to explicitly provide the class type in template parameter.

#include <functional>
#include <iostream>

struct Callback_t {
    void myCallback(int)
    {
        std::cout << "You called me?";
    }
};

class SomeClass {
public:
    SomeClass() : callback() { }
    typedef std::function<void(Callback_t*, int)> Callback;
                           //  ^^^^^^^^^^^

    void registerCallback(const Callback& c)
    {
        callback = c;
    }

    void callOn(Callback_t* p)
    {
        callback(p, 42);
    }
private:
    Callback callback;
};

int main()
{
    SomeClass sc;
    sc.registerCallback(&Callback_t::myCallback);

    Callback_t cb; // we need an instance of Callback_t to call a member on
    sc.callOn(&cb);
}

Output: You called me?;

查看更多
forever°为你锁心
4楼-- · 2019-03-06 12:56

the function void (*)(unsigned char*, int) is a free function, which is a different type from void (SomeOtherClass::*)(unsigned char*, int), thus the error. You need an object to call the latter, while the former is a free function.

Look at the possible solutions listed in the Boost documentation

Another possibility is that your SomeOtherClass::myCallback is private, so you do not have access to it.

查看更多
闹够了就滚
5楼-- · 2019-03-06 12:58

Why all this complicated mumbo-jumbo?

Why not create a class as thus (for example)

Class MouseOverEventCallBack
{
   public:
      virtual void RunMouseOverCallback() = 0;
};

Then just create classes that inherit this class (and redefine the method RunMouseOverCallback)

Then Register function just needs to be

void registerCallback(MouseOverEventCallBack *callbackObject); // possible could use a reference

The register method will just call the method and the object will have all that it needs.

Seems a bit simpler. Let the compiler do the work with pointers to functions etc.

查看更多
登录 后发表回答