添加事件处理程序的好方法?

时间:2010-10-10 04:25:57

标签: c++ event-handling

我正在制作游戏的Gui API。基本上我在我的类中有事件回调,它们是函数指针。我想直接让user =函数指针ex:

widget->OnPaintCallback = myPaintFunc;

但我不喜欢我不能检查NULL或做任何其他事情。这也让我的课堂感到暴露。

我还想过为每个回调设置一个setter,但是这会在课堂上变得混乱(我有超过50个)

然后我想到了一个函数,它要求一个字符串来指示处理程序所针对的事件及其函数指针。但是,这将不必要地引用文档来了解字符串,甚至更加混淆自定义的未记录的小部件。

是否有更好,更清洁的选择?

由于

casablankca的解决方案有多个参数吗?

4 个答案:

答案 0 :(得分:1)

我会建议Boost.Signals库。像这样:

class Widget
{
public:
    boost::signal<void (Paint &)> onPaint;
    boost::signal<void (MouseMove &)> onMouseMove;
    // ... etc
};

// later...

Widget myWidget;
myWidget.onPaint.connect(myPaintFunc);

// and to fire the event:

void Widget::DoPaint()
{
    Paint data;
    data.whatever = foo;

    onPaint(data);
}

这有几个好处:

  1. 如果您的编译器支持,可以将它与boost::bind(或bind的C ++ 0x版本)结合使用,以允许您将成员函数绑定到事件处理程序。
  2. 您可以将多个处理程序附加到单个事件。如果只使用函数指针,则一次只能分配一个函数指针。
  3. 信号强大且灵活。您可以拥有采用不同类型和数量参数的信号,并且它们都将在编译时解析。

答案 1 :(得分:1)

我建议您查看boost.signals库或libsigc++。这些是用于管理事件处理程序之类的非常通用的库。他们做的比你想做的要多得多,但是他们会为你提供你想要的设计中你想要的东西的想法。

您使用回调的次数越多,您就越会意识到您需要更多这些库中的功能(例如注册多个回调,绑定参数,更灵活的类型等)。所以即使你最终做了更简单的东西,从成熟的设计中学习会很有帮助。

答案 2 :(得分:0)

您可以为所需的每种类型的事件处理程序执行接口。与Java不同。所以例如你会有

class PaintCallback {
public:
  virtual void paint() = 0;
};

您的事件处理程序将从抽象类继承并实现paint方法。在widget类中,您将为每个处理程序保留一个指针(或集合)。

答案 3 :(得分:0)

  

但我不喜欢我不能检查NULL或做任何其他事情

如何使回调(OnPaintCallback)成为重载operator =的类的对象,这样你就可以进行任何额外的检查并在出现问题时抛出异常。您还可以重载operator (),以便可以像调用简单函数一样调用此对象。

更新:对于可变数量的函数参数,没有通用的方法,但如果您的最大N有限且很小,您可以使用模板特化,例如:(I为了清楚起见,省略了构造函数,operator =和其他细节)

template<typename T, int N>
class Callback {
};

template<typename T>
class Callback<T, 1> {
  T func;

  template<typename A1>
  void operator ()(A1 arg1) {
    func(arg1);
  }
};

template<typename T>
class Callback<T, 2> {
  T func;

  template<typename A1, typename A2>
  void operator ()(A1 arg1, A2 arg2) {
    func(arg1, arg2);
  }
};

我知道这是一种hacky方式,但至少你的用户不会看到任何这样的:他们将为所有回调获得相同的界面。