在C ++中实现可用回调的好方法

时间:2009-09-04 09:29:06

标签: c++ coding-style callback

我有一个用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;
}

有什么人可以认为这种方法很脏吗?还有更好的吗?

7 个答案:

答案 0 :(得分:10)

您的方法要求回调函数是自由函数或类的静态成员。它不允许客户端使用成员函数作为回调。对此的一个解决方案是使用boost::function作为回调的类型:

typedef boost::function<void (MenuItem*)> callback_type;
AddItem(const std::string& s, const callback_type& callback = callback_type());

然后,客户可以使用boost::bindboost::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::functionboost:bind。学习它会使你的功能绑定容易一百倍。

答案 5 :(得分:1)

阅读this白皮书。它通过非常详细地分析性能,可用性和其他权衡来构建回调机制的各种技术。我发现它很难读: - (

答案 6 :(得分:0)

您可以使用functor来封装回调。这将允许您使用C风格的函数或对象接口来提供回调。