模板化,多态回调是个好主意吗?

时间:2010-11-12 04:23:14

标签: c++ templates polymorphism

我正在为游戏制作一个Gui Api。用户总是可以在窗口小部件上使用继承并覆盖,但我想要回调。我想使用模板化的回调系统:

所以,如果他们想要一个鼠标,那么他们从带有鼠标的模板化回调基础版继承:

所以基数看起来像这样:

template <typename T>

class AguiEventCallback {

public:
virtual void callback(AguiWidget* sender, T arg) = 0;

};

将模板与这样的多态混合是一个好主意吗?我最好为我需要的每种类型(鼠标,键盘,游戏手柄等)创建回调吗?

由于

4 个答案:

答案 0 :(得分:3)

看一下boost :: function和boost :: bind。接受具有特定事件的已定义参数列表的函数对象,并且调用者可以执行他们想要的操作。

这为回调实现提供了很大的灵活性,生成事件的对象需要更少的回调实现知识。

例如:

 typedef boost::function<void (AguiWidget* sender)> CallbackFunc;
 void register_callback(CallbackFunc const& f);

客户:

class Caller {
    void do_register() { register_callback(bind(&Caller::event, this, 123, _1)); }

    void event(int arg, AguiWidget* sender) { ... }
};

只显示function / bind,忽略了许多其他问题;例如。内存管理,对象生存期。

答案 1 :(得分:1)

有时使用模板的方式很好。由于您必须为模板提供虚拟析构函数

,因此存在一些问题
  • 如果您内联虚拟析构函数(与大多数模板函数一样),某些编译器会发现很难坚持单一定义规则,特别是如果库是跨库使用的。

  • 如果不内联虚拟析构函数,则必须实例化要与该模板一起使用的每个类型。这是我自己喜欢的方法。

对于回调,您可以选择使用boost :: function。这避免了必须从模板派生类,使用new创建它们,并可能将它们粘贴到某个地方的shared_ptr中。我发现,boost :: function作为回调的缺点是如果出现问题就很难调试。小心那个问题。

答案 2 :(得分:0)

暂时接受您的虚拟调度解决方案,您的模板化方法保证回调函数名称和参数的一致性。遗憾的是,这将迫使许多其他代码消除歧义,即调用/覆盖哪个回调,可能导致更多麻烦而不是好。

那就是说,janm说存在其他选择。函子更强大(您可以在运行时在现有对象上更改它们,您可以拥有观察者列表)但也必须在正确的时间进行初始化(纯虚函数有效地提醒程序员在编译时提供它们) ,并引入更多种类的运行时状态来推理和理解。

您也可以使用模板策略或奇怪的重复模板模式在编译时提供行为,允许内联,死代码消除,特定于类型的行为和其他优化。

答案 3 :(得分:0)

除了这里的其他答案,您可以查看boost :: signal库。它实现了一个信号/插槽机制,这对GUI来说确实很有用。性能不如您预期的那么好(成本高于对虚拟方法的调用),但对于GUI来说,它很好。

boost :: signal库也可以与boost :: bind一起使用,这个组合非常强大。

我不喜欢将继承用于回调。它大部分时间只用一种方法产生很多类。它是C ++而不是Java。你有功能,使用它们:)