将任何类的任何成员函数作为回调函数传递
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::function
和 boost::bind
(或 std::function
和 std::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<void(Button*)>
对象。这些是运行时多态的,可以与支持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 上的蓝牙相关的参数回调函数传递?