C++ 中的回调给班级成员

发布于 2024-10-15 23:30:42 字数 1338 浏览 2 评论 0原文

我们为客户提供了一个简单的通讯库。

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

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);
};

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(); //<- ???
}

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

感谢您的帮助!

We have a simple communication library for our customers.

My problem is: How can I save a pointer to a method from a class of our customer?

Library.h is the header file with all the methods our customer need to establish a communication.

library.cpp is our code. Somewhere here i have to save the pointers to the method of the callback function from our customer.

customer.cpp is an example how a customer uses our library.

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);
};

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(); //<- ???
}

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

Thanks for any help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

稀香 2024-10-22 23:30:42

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

struct Callback {
  virtual ~Callback(){}
  virtual void operator()(int param)=0;
};

此类允许您的实现无需了解需要回调的代码。当然,要调用一个类,您确实需要一个了解其目标的 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);
  }
};

要从其类创建回调的实例,代码将看起来像这样。调用也很简单:

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();
  }
};

总之: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{ ... };

The basic idea is, you define an abstract Callback class, which actually gets passed to your interface. This one calls back to a function passing a single int parameter:

struct Callback {
  virtual ~Callback(){}
  virtual void operator()(int param)=0;
};

This class allows YOUR implementation to be free from knowledge of the code you need to call back into. Of course, to call into a class, you do need an instantiation of Callback that DOES have knowledge of its target. So you then also provide a templated child class that makes it easy for users of your Library to to bind a method in one of their classes to an instance of the generic 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);
  }
};

To create an instance of the callback from their class, code would look like this. And the invocation is simple too:

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();
  }
};

In Summary: Library.h then would look like this. Define the abstract callback class, your library class, and the templated utility class that the customer uses to wrap their their class and its callback method with:

// 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{ ... };
撑一把青伞 2024-10-22 23:30:42

基本思想是在虚拟函数调用后面隐藏对象和函数(代码中的ObjectFunction)的确切类型,并将两者包装在抽象接口中(这是“类型擦除”惯用语)。

然后,您可以让您的客户通过模板接口从您的“基本回调”类型派生。

有关教程,请参阅此网站上的第 4 部分。或者看看 Boost.Function 和 < a href="http://www.boost.org/doc/libs/1_45_0/libs/bind/bind.html" rel="nofollow">Boost.Bind 工作(他们正是这样做的,尽管使用稍微强大的界面)

The basic idea is to hide the exact type of the object and function (Object and Function in your code) behind a virtual function call, and wrap both in an abstract interface (This is the 'type erasure' idiom).

You can then let your customers derive from your "basic callback" type via a template interface.

For a tutorial, see part 4. on this website. Or take a look at how Boost.Function and Boost.Bind work (they do exactly that, although with a slightly more powerful interface)

数理化全能战士 2024-10-22 23:30:42

最简单、最灵活的方法是使用 std::function。

假设我有一个函数(但这也可以是一个类),它需要调用传递给它的另一个函数。我这样定义这个函数:

#include <functional>         // defines std::function
#include <iostream>

typedef std::function<bool(int)> FunctionPtr;

void myFunction (const FunctionPtr &functionPtr)
{
std::cout << "Before" << std::endl;
functionPtr(123);
std::cout << "After" << std::endl;
}

有关如何使用它的第一个示例是使用全局函数(或静态方法),如下所示:

bool myFunPtr(int i)
   {
   std::cout << "FunPtr:" << i << std::endl;
   return true;
   }

int main()
{
myFunction (myFunPtr);
}

我只是将函数指针传递给 myFunction。

我还可以使用 lambda 表达式,如下所示:

int main()
{
myFunction ([](int i)->bool{std::cout << "Lambda:" << i << std::endl;return true;});
}

第三个示例(这可能是您想要的)是传递已定义函数运算符的类实例,如下所示:

class X
   {
   public:
      X(std::string s) : m_s(s) {}
      bool operator()(int i)
         {
         std::cout << m_s << i << std::endl;
         return true;
         } 
   private:
      std::string m_s;
   };

int main()
{
myFunction ([](int i)->bool{std::cout << "Lambda:" << i << std::endl;return true;});

myFunction (myFunPtr);

X x1("x1:");
myFunction (x1);

X x2("x2:");
myFunction (x2);
}

正如您所见,使用 std::函数中,我可以传递 3 种不同类型的“函数引用”(函数指针、lambda 和函子)。

The easiest and most flexible way is to use std::function.

Suppose I have a function (but this could be a class as well), which needs to call another function passed to it. I define this function like this:

#include <functional>         // defines std::function
#include <iostream>

typedef std::function<bool(int)> FunctionPtr;

void myFunction (const FunctionPtr &functionPtr)
{
std::cout << "Before" << std::endl;
functionPtr(123);
std::cout << "After" << std::endl;
}

A first example on how to use this is using a global function (or static method), like this:

bool myFunPtr(int i)
   {
   std::cout << "FunPtr:" << i << std::endl;
   return true;
   }

int main()
{
myFunction (myFunPtr);
}

I just pass the function pointer to myFunction.

I can also use a lambda expression, like this:

int main()
{
myFunction ([](int i)->bool{std::cout << "Lambda:" << i << std::endl;return true;});
}

The third example (and which is probably what you want), is to pass a class instance that has defined the function-operator, like this:

class X
   {
   public:
      X(std::string s) : m_s(s) {}
      bool operator()(int i)
         {
         std::cout << m_s << i << std::endl;
         return true;
         } 
   private:
      std::string m_s;
   };

int main()
{
myFunction ([](int i)->bool{std::cout << "Lambda:" << i << std::endl;return true;});

myFunction (myFunPtr);

X x1("x1:");
myFunction (x1);

X x2("x2:");
myFunction (x2);
}

As you can see, using std::function, I can pass 3 different types of 'references to functions' (function pointers, lambda's and functors).

书信已泛黄 2024-10-22 23:30:42

下面的代码似乎以某种方式工作,但恕我直言,整个设计非常可疑。
http://codepad.org/9QDcMJAg

#include <stdio.h>

struct Library {
  template <class Object,class Function>
  void SetCallback(Object &obj, Function f);
};


struct Object {
  void Method( void );
};

typedef void (Object::*Function)(void);

struct T_CUSTOMER {
  Object o;  
  Function f;
};

T_CUSTOMER customer;

template <class Object,class Function>
void Library::SetCallback( Object &obj, Function f ) {
  customer.o = obj;
  customer.f = f;  
}

void someFunction(void) {
  (customer.o.*customer.f)();
}

struct AnyCustomerClass : Object {
  Library lib;

  AnyCustomerClass() {
    lib.SetCallback( *this, (Function)&AnyCustomerClass::callback );
  }

  void callback(void) {
    printf( "callback!\n" );
  }
};

int main( void ) {

  AnyCustomerClass a;

  someFunction();

}

The code below seems to work somehow, but imho the whole design is very suspicious.
http://codepad.org/9QDcMJAg

#include <stdio.h>

struct Library {
  template <class Object,class Function>
  void SetCallback(Object &obj, Function f);
};


struct Object {
  void Method( void );
};

typedef void (Object::*Function)(void);

struct T_CUSTOMER {
  Object o;  
  Function f;
};

T_CUSTOMER customer;

template <class Object,class Function>
void Library::SetCallback( Object &obj, Function f ) {
  customer.o = obj;
  customer.f = f;  
}

void someFunction(void) {
  (customer.o.*customer.f)();
}

struct AnyCustomerClass : Object {
  Library lib;

  AnyCustomerClass() {
    lib.SetCallback( *this, (Function)&AnyCustomerClass::callback );
  }

  void callback(void) {
    printf( "callback!\n" );
  }
};

int main( void ) {

  AnyCustomerClass a;

  someFunction();

}
绝情姑娘 2024-10-22 23:30:42

感谢您的回答,但我在实现方面仍然存在问题(我通常用java或C(微控制器)进行编程。从未想过在C++中实现这一点对我来说会如此复杂))

我喜欢使用Chris的建议贝克.

library.h

// This is the header file what our customer gets
struct Callback {
  virtual void operator()(int param)=0;
};
class Library {
    Callback *cb;
  public:
    void SetCallback(Callback*);
};
template<class T>
class ClassCallback : public Callback {
  T* _classPtr;
  typedef void(T::*fncb)(int dwTime);
  fncb _cbProc;
public:
  ClassCallback(T* classPtr,fncb cbProc):_classPtr(classPtr),_cbProc(cbProc){}
  virtual void operator()(int param){
    (_classPtr->*_cbProc)(param);
  }
};

customer.cpp

class T_Customer{
private:
    Library lib;
    void OnCallback(int param){
          printf("Parameter: %i\n",param);
      }
    };
public:
    T_Customer(){
        lib.SetCallback(new ClassCallback<T_Customer>(this,&T_Customer::OnCallback));
    }
};

Library.cpp

void Library::SetCallback(Callback *callback){
    cb = callback;
}


void executeCallback(){
  if(cb)
    (*cb)();
}

int main(void){
    T_Customer customer;
    executeCallback();
    return 0;
}

Thanks for the answers, but i still have problems with the implementation (I normaly program in java or in C (microcontoller). Never thought it would be so complicated for me to realise this in c++))

I like to use the suggestion from Chris Becke.

library.h

// This is the header file what our customer gets
struct Callback {
  virtual void operator()(int param)=0;
};
class Library {
    Callback *cb;
  public:
    void SetCallback(Callback*);
};
template<class T>
class ClassCallback : public Callback {
  T* _classPtr;
  typedef void(T::*fncb)(int dwTime);
  fncb _cbProc;
public:
  ClassCallback(T* classPtr,fncb cbProc):_classPtr(classPtr),_cbProc(cbProc){}
  virtual void operator()(int param){
    (_classPtr->*_cbProc)(param);
  }
};

customer.cpp

class T_Customer{
private:
    Library lib;
    void OnCallback(int param){
          printf("Parameter: %i\n",param);
      }
    };
public:
    T_Customer(){
        lib.SetCallback(new ClassCallback<T_Customer>(this,&T_Customer::OnCallback));
    }
};

Library.cpp

void Library::SetCallback(Callback *callback){
    cb = callback;
}


void executeCallback(){
  if(cb)
    (*cb)();
}

int main(void){
    T_Customer customer;
    executeCallback();
    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文