我有一个类,鼠标,而不是处理鼠标事件。它包含许多静态函数,用于简单的“where it it,etc”调用,但它也有一些非静态成员,即当它用作对象时的一些事件处理内容。我遇到了麻烦,但我如何允许任何对象订阅事件。在我的Mouse.h文件中,我有以下声明:(原谅语法错误,这是来自内存)
typedef void (*MouseEvent)(Point pos,MouseButton button)
class Mouse {
MouseEvent m_downEvent;
//...
void HookMouseDown(MouseEvent handler);
void OnMouseDown();
}
......并在实施中......
void Mouse::HookMouseDown(MouseEvent handler) {
if (handler != NULL) m_downEvent = handler;
}
void Mouse::OnMouseDown() {
if (m_downEvent != NULL) m_downEvent(m_pos,m_button);
}
现在在我的订阅者代码中,以这种方式连接事件似乎合乎逻辑:
m_mouse.HookMouseDown(&MyClass::MouseDown);
但是我的编译器(MVC2008)并不喜欢这样一个事实,即我将它传递给指向成员函数的指针而不是指向自由指针的函数。经过一些研究,我发现将typedef更改为
typedef void (MyClass::*MouseEvent)(Point pos,MouseButton button)
它不会抱怨并且可以正常工作,但问题是这会将事件的订阅者限制为仅 MyClass对象。 我是否需要获取模板以允许任何对象订阅这些事件?或者首先允许任何东西消耗鼠标事件是不好的设计?
答案 0 :(得分:3)
它不会抱怨并且可以正常工作,但问题是这会将事件的订阅者限制为只有MyClass对象。
不,您也可以通过派生类实例“调用”该成员。
无论如何,使用std :: mem_fun_ptr(c ++ 03)std :: function<>这个问题已经解决了很多次。 (c ++ 0x),std :: bind(c ++ 0x)和boost :: bind。
以下是完整示例,请参阅直播https://ideone.com/mut9V :
#include <iostream>
struct MyBase
{
virtual void DoStuff(int, float) { std::cout << "Base" << std::endl; }
};
struct MyDerived : MyBase
{
virtual void DoStuff(int, float) { std::cout << "Derived" << std::endl; }
};
int main()
{
typedef void (MyBase::*memfun)(int, float);
memfun event(&MyBase::DoStuff);
MyBase base;
MyDerived derived;
(base.*event)(42, 3.14);
(derived.*event)(42, 3.14);
}
答案 1 :(得分:1)
要使类Mouse
处理指向任意类的成员函数的指针,可以将其作为模板:
template<class T>
class Mouse {
typedef void (T::*MouseEvent)(Point pos,MouseButton button);
MouseEvent m_downEvent;
//...
void HookMouseDown(MouseEvent handler);
void OnMouseDown();
}
答案 2 :(得分:0)
或者首先允许任何东西消耗鼠标事件是不好的设计?
我认为使用基于事件的设计是相当不错的。另一方面,支持自由函数和成员函数是一件痛苦的事。特别是如果你还要提供调用这个函数的实例。
巧合的是,我偶然发现了一个Delegate
实施,它完全解决了这个问题。看看这个interesting article。
HookMouseDown
现在可以返回对内部委托的引用,然后可以绑定到自由函数或成员函数:
mouse.HookMouseDown().Bind<MyClass, &MyClass::MyMember>(myinstance);
答案 3 :(得分:0)
你真的想要std :: function和std :: bind / lambdas(函数/绑定在Boost中也可用)。这足以解决问题。