将任何类的任何成员函数作为回调函数传递

Posted

技术标签:

【中文标题】将任何类的任何成员函数作为回调函数传递【英文标题】:Pass any member function of any class as a Callback function 【发布时间】:2011-05-04 19:32:02 【问题描述】:

我正在开发一个包含一些按钮的 OpenGL 菜单。我希望能够将任何类的操作(成员函数(具有固定签名)!)与按下按钮时执行的按钮相关联。我现在可以做到,但仅限于一种类型。我希望能够为我的回调使用任何类的任何成员函数。

现在我正在这样做:

#define BUTTONCALLBACK(Func) bind1st( mem_fun( &ClassICanSupport::Func ), this )

然后我可以像这样创建一个按钮:

Button* b = new Button("Bla", BUTTONCALLBACK(functionIWanttoCall));

回调函数具有以下签名:

void callback(Button* source);

当我按下按钮时,我可以执行我传递的回调函数。

我查看了 boost::bind 但我真的找不到解决问题的方法。此外,我所有的类都是从类 Object 派生的,所以我想到了一个 void*,我可以通过一些 typeid hack 将其转换为正确的类,但我无法让它工作。最后我总是有一个问题,我无法完全消除回调函数的类类型(这对于将函数指针保存在我的按钮类中是必要的)并且仍然能够调用该函数。

你知道如何解决这个问题吗?

【问题讨论】:

【参考方案1】:

不要使用指针,使用 boost::functionboost::bind(或 std::functionstd::bind 如果 C++0x),类似

// in Button class (or whatever signature you need)
Button(const std::string&, boost::function<void(Button*)> callback) // ...
// you can then use callback as a function

// in calling code
Button *b = new Button("..", boost::bind(&Class::func, this));

【讨论】:

【参考方案2】:

您应该使用function&lt;void(Button*)&gt; 对象。这些是运行时多态的,可以与支持void operator()(Button*) 的任何对象一起使用。您可以在 Boost、TR1 和 C++0x 中找到一个。 boost::bind 适用于这些对象。

【讨论】:

【参考方案3】:

好吧,如果您不想使用 Boost 或无法访问 C++0x,最简单的方法是使用虚函数。

#include <iostream>

// fwd declare
class Button;

class BtnCallbackBase
public:
  virtual void operator()(Button*) = 0;
;

template<class C>
class BtnCallback : public BtnCallbackBase
private:
  typedef void (C::*callback_func)(Button*);

  C* _object;
  callback_func _onclick;

public:
  BtnCallback(C* obj, callback_func func)
    : _object(obj)
    , _onclick(func)
  

  virtual void operator()(Button* btn)
    (_object->*_onclick)(btn);
  
;


class Button
public:
  Button()
    : _onclick(0)
  

  void Click()
    if(_onclick != 0)
      (*_onclick)(this);
  

  template<class C>
  void RegisterCallback(C* obj, void (C::*func)(Button*))
    // cleanup old callback, deleting null pointer is a noop
    delete _onclick;
    _onclick = new BtnCallback<C>(obj,func);
  

  ~Button()
    delete _onclick;
  

private:
  BtnCallbackBase* _onclick;
;

class MyClass
public:
  void ExampleCallback(Button* btn)
    std::cout << "Callback works!\n";
  
;

int main()
  Button btn;
  MyClass test;

  btn.RegisterCallback(&test, &MyClass::ExampleCallback);

  btn.Click();

Full example on Ideone.

【讨论】:

【参考方案4】:

如果您想在不使用 Boost 库/不使用新的 C++ 功能的情况下解决您的问题,那么最好的选择之一是 Danny Kalev / Herb Sutter 讨论的 Generic Callbacks Dispatcher

http://www.gotw.ca/gotw/083.htm

【讨论】:

以上是关于将任何类的任何成员函数作为回调函数传递的主要内容,如果未能解决你的问题,请参考以下文章

如何实现类的成员函数作为回调函数

如何将成员函数作为与 Windows 上的蓝牙相关的参数回调函数传递?

如何使用 C++ lambda 将成员函数指针转换为普通函数指针以用作回调

C++ 指向具有匹配函数签名的任何类的成员函数的指针

使用成员函数求解方程 C++

c++,类的对象作为形参时一定会调用复制构造函数吗?