我有一个用C ++编写的自定义Menu类。为了将代码分成易于阅读的函数,我正在使用Callbacks。
由于我不想将Singletons用于菜单主机,因此我提供了另一个参数(目标),该参数将作为第一个参数提供给回调(缺少“this”引用的某种解决方法)。
登记签名
AddItem(string s, void(*callback)(void*,MenuItem*), void* target = NULL)
注册示例
menu->AddItem(TRANSLATE, "translate", &MyApp::OnModeSelected);
处理程序的示例
/* static */
void MyApp::OnModeSelected(void* that, MenuItem* item) {
MyApp *self = (MyApp*)that;
self->activeMode = item->text;
}
有什么人可以认为这种方法很脏吗?还有更好的吗?
答案 0 :(得分:10)
您的方法要求回调函数是自由函数或类的静态成员。它不允许客户端使用成员函数作为回调。对此的一个解决方案是使用boost::function作为回调的类型:
typedef boost::function<void (MenuItem*)> callback_type;
AddItem(const std::string& s, const callback_type& callback = callback_type());
然后,客户可以使用boost::bind或boost::lambda传递回调:
menu->AddItem("Open", boost::bind(&MyClass::Open, this));
另一种选择是使用boost::signals,允许多个回调注册同一事件。
答案 1 :(得分:8)
我喜欢你的方法。一种替代方法是声明一个接口,这在某种意义上是回调的“OO等价物”:
class IMenuEntry {
public:
virtual void OnMenuEntrySelected(MenuItem* item) = 0;
};
注册签名将成为
AddItem(string s, IMenuEntry * entry);
方法实现
class MyApp : public IMenuEntry {
public:
virtual void OnMenuEntrySelected(MenuItem* item){
activeMode = item->text;
}
}
接口方法可以避免缺少this
指针的“void * workaround”。
答案 2 :(得分:3)
您可以查看使用boost::bind。
menu->AddItem(TRANSLATE,
"translate",
boost::bind( &MyApp::OnModeSelected, this, _1, _2 ));
答案 3 :(得分:1)
除了函数指针签名难以阅读外,我没有看到任何错误。但是,我可能observer模式来实现这一点。
答案 4 :(得分:1)
我强烈建议您查看boost::function和boost:bind。学习它会使你的功能绑定容易一百倍。
答案 5 :(得分:1)
阅读this白皮书。它通过非常详细地分析性能,可用性和其他权衡来构建回调机制的各种技术。我发现它很难读: - (
答案 6 :(得分:0)
您可以使用functor来封装回调。这将允许您使用C风格的函数或对象接口来提供回调。