我正在开发一个包含一些按钮的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的正确类,但我无法使它工作。最后,我总是遇到这样的问题:我无法完全消除回调函数的类类型(这对于在我的按钮类中保存函数指针是必要的)并且仍然可以调用该函数。
你知道如何解决这个问题吗?
答案 0 :(得分:3)
不要使用指针,将boost::function
与boost::bind
一起使用(如果是C ++ 0x,则使用std::function
和std::bind
),例如
// 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));
答案 1 :(得分:1)
您应该使用function<void(Button*)>
对象。这些是运行时多态,可以与支持void operator()(Button*)
的任何对象一起使用。你可以在Boost,TR1和C ++ 0x中找到一个。 boost::bind
适用于这些对象。
答案 2 :(得分:1)
嗯,最简单的方法是使用虚函数,如果你不想引入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();
}
答案 3 :(得分:0)
如果您想在不使用Boost库的情况下解决问题,而不使用新的C ++功能,那么最好的选择之一是 Danny Kalev / Herb Sutter讨论的 Generic Callbacks Dispatcher 。< /强>