用C++回调给类成员

Sas*_*cha 6 c++ methods function callback

我们为客户提供简单的通信库.

我的问题是:如何从我们客户的类中保存指向方法的指针?

Library.h 是头文件,包含客户建立通信所需的所有方法.

library.cpp是我们的代码.在某处我必须保存指向我们客户的回调函数方法的指针.

customer.cpp 是客户如何使用我们的库的一个例子.

library.h:

// This is the header file what our customer gets
class Library {
  public:
    template <class Object, class Function>
    void SetCallback(Object &obj, Function f);
};
Run Code Online (Sandbox Code Playgroud)

library.cpp:

struct T_CUSTOMER {
    Object o;   // <- ???
    Function f; // <- ???
} customer;

void Library::SetCallback(Object &obj, Function f) {
    //Saving the method from our costumer
    customer.o = obj;   // <- ???
    customer.f = f;     // <- ???
}

void someFunction(void) {
    // here i want to call the method from the customer
    customer.o->customer.f(); //<- ???
}
Run Code Online (Sandbox Code Playgroud)

customer.cpp中:

class AnyCustomerClass {
    private:
        Library lib;

    public:
        AnyCustomerClass() {
            //< here the customer sets his method which I should call
            lib.SetCallback(this, &AnyCustomerClass::callback());
        }

        callback() {
            // do something
        }
}
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助!

Chr*_*cke 7

基本思想是,您定义一个抽象的Callback类,它实际上被传递给您的接口.这个回调函数传递一个int参数:

struct Callback {
  virtual ~Callback(){}
  virtual void operator()(int param)=0;
};
Run Code Online (Sandbox Code Playgroud)

这个类允许你的实现不需要你需要回调的代码的知识.当然,要调用一个类,你需要一个回调的实例,它已知道它的目标.因此,您还提供了一个模板化子类,使您的库用户可以轻松地将其中一个类中的方法绑定到通用Callback的实例: -

template<class T>
class ClassCallback : public Callback {
  T* _classPtr;
  typedef void(T::*fncb)(int param);
  fncb _cbProc;
public:
  ClassCallback(T* classPtr,fncb cbProc):_classPtr(classPtr),_cbProc(cbProc){}
  virtual void operator()(int param){
    (_classPtr->*_cbProc)(param);
  }
};
Run Code Online (Sandbox Code Playgroud)

要从类中创建回调实例,代码将如下所示.调用也很简单:

struct CMyClass {
  Library* _theLibrary;
  CMyClass(Library* init):_theLibrary(init){
    Callback* pCB = new ClassCallback<CMyClass>(&myClass,&CMyClass::OnCb);
    _theLibrary->SetCallback(pCB);
  }
  void OnCb(int){
    // callback triggered
  }
  void Run(){
    _theLibrary->DoWork();
  }
};
Run Code Online (Sandbox Code Playgroud)

总结:Library.h然后会是这样的.定义抽象回调类,库类以及客户用来包装其类及其回调方法的模板化实用程序类:

// This is the header file what our customer gets
struct Callback {... };
class Library {
  Callback* _pcb;
  public:
    void SetCallback(Callback* pcb){_pcb=pcb;}
    void DoWork(){
      int status=0;
      (*pcb)(status);
    }
    ~Library(){delete _pcb;}

};
template<class T> struct ClassCallback{ ... };
Run Code Online (Sandbox Code Playgroud)


ltj*_*jax 5

基本思想是在虚函数调用后隐藏对象和函数(Object以及Function代码中)的确切类型,并将它们包装在抽象接口中(这是'类型擦除'习语).

然后,您可以通过模板界面让您的客户从"基本回调"类型中获得.

有关教程,请参阅本网站上的第4部分.或者看一下Boost.FunctionBoost.Bind是如何工作的(他们正是这样做的,尽管有一个稍微强大的界面)