我正在制作游戏的Gui API。基本上我在我的类中有事件回调,它们是函数指针。我想直接让user =函数指针ex:
widget->OnPaintCallback = myPaintFunc;
但我不喜欢我不能检查NULL或做任何其他事情。这也让我的课堂感到暴露。
我还想过为每个回调设置一个setter,但是这会在课堂上变得混乱(我有超过50个)
然后我想到了一个函数,它要求一个字符串来指示处理程序所针对的事件及其函数指针。但是,这将不必要地引用文档来了解字符串,甚至更加混淆自定义的未记录的小部件。
是否有更好,更清洁的选择?
由于
casablankca的解决方案有多个参数吗?
答案 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);
}
这有几个好处:
boost::bind
(或bind
的C ++ 0x版本)结合使用,以允许您将成员函数绑定到事件处理程序。答案 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方式,但至少你的用户不会看到任何这样的:他们将为所有回调获得相同的界面。