不同类之间非静态函数的C++回调

标签 c++ boost callback function-pointers

我有一个 A 类,我打算在它与设备驱动程序交互时将其放入共享库中。

我有一个 B 类,将来可能是 C、D、E...,它将使用共享库中的 A 类。

我想要在类 A 中设置回调函数的功能,以便当特定事件发生时,类 B、C、D、E ... 的非静态成员函数应由类 A 调用。

我在谷歌上搜索了 C++ 中的回调函数,但发现 C 风格的回调定义不支持非静态成员函数。

可以使用函数指针来完成吗?

请在不违反 OOPS 概念的情况下对 C++ 中的回调提出一些建议。

我还想到了一个名为“Boost”的库,它提供了类似的功能,但我想尽可能避免额外库的开销。是否建议将 Boost 用于回调函数?

编辑: B、C、D、E 将不共享任何层次结构,它们将是完全独立的类。但是它们都会有 A 类的对象。A 类也会有一个公共(public)函数来设置回调函数。

最佳答案

如果您真的想避免多态函数包装器的几乎不重要的开销,一个选择是使这些函数静态并让它们采用“用户数据”void* 参数,指向该函数所属的类的适当实例。在静态函数内部,然后转换回适当的类型:

#include <iostream>

struct A{
  typedef void (*callback_type)(void*, int);
  callback_type callback;
  void* user_data;
  void set_callback(callback_type cb, void* ud){
     callback = cb; user_data = ud;
  }
  void invoke(){ callback(user_data, 42); }
};

struct B{
  static void cb_foo(void* vself, int data){
    B* self = static_cast<B*>(vself);
    self->foo(data);
  }
  void foo(int data){ std::cout << data * 2 << "\n"; }
};

struct C{
  static void cb_bar(void* vself, int data){
    C* self = static_cast<C*>(vself);
    self->bar(data);
  }
  void bar(int data){ std::cout << data / 2 << "\n"; }
};

int main(){
  A a;
  B b;
  a.set_callback(&B::cb_foo, &b);
  a.invoke();
  C c;
  a.set_callback(&C::cb_bar, &c);
  a.invoke();
}

Live example on Ideone.

不过,我个人会推荐使用 std::function,因为上面的内容在可接受的回调方面受到严格限制。 std::function 是一个多态函数包装器,这意味着它可以采用普通函数指针、成员函数指针甚至仿函数(函数对象)并以相同的方式调用它们。与允许您将参数绑定(bind)到函数的 std::bind 一起,您可以轻松回调成员函数。 Boost 也提供它们(Boost.FunctionBoost.Bind)。

#include <iostream>
#include <functional> // C++11
//#include <boost/function.hpp>
//#include <boost/bind.hpp>

struct A{
  std::function<void(int)> callback;
  void invoke(){ callback(42); }
};

struct B{
  void foo(int data){ std::cout << data * 2 << "\n"; }
};

struct C{
  void bar(int data){ std::cout << data / 2 << "\n"; }
};

int main(){
  using namespace std::placeholders; // namespace for argument placeholders for std::bind
                                     // not needed for Boost.Bind
  A a;
  B b;
  a.callback = std::bind(&B::foo, &b, _1);
  a.invoke();
  C c;
  a.callback = std::bind(&C::bar, &c, _1);
  a.invoke();
};

Live example on Ideone.

基本上 std::bind 会自动执行您在第一个版本中必须手动执行的操作,它会保存对象指针并调用其成员函数。但是,它不是通过 void* 指针来执行此操作,而是 std::bind 为每个不同的对象指针返回不同的绑定(bind)器类型。这就是您需要 std::function 的原因,因为它不关心您传递给它的内容。

关于不同类之间非静态函数的C++回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11522422/

相关文章:

c++ - boost::lexical_cast 对于 c++11 stoi、stof 和 family 是否是多余的?

cakephp 行为 afterFind 没有在相关模型上调用

javascript - JS : Callback function is not executing

c++ - 更改 ascii 代码并将字符添加到 C++ 中的字符串

arduino 的 C++ - 错误 : class does not name a type

C++ 通过重定向 cout 将 stdout 复制到文件

c++ - 如何遍历一个boost::multi_array

javascript - Mongoose - 通过回调函数返回设置虚拟值

c++ - 优化复合 std::functions

c++ - 从 std::list 中移除/删除