所以,我倾向于在某种程度上不同意 Uri。
如果你正在实现观察者模式,你想要的是能够说:
“当对象 X 执行 Y 时,我想执行代码 Z”。
采用纯粹基于抽象类的方法并不是最好的方法。为每个事件处理程序要求一个单独的类(尤其是在 C++ 中)是多余的。如果您来自 Java,那么他们就是这样做的。然而,Java 有 2 个特性使这有点烦人:匿名类和“实例”成员类。这允许您为同一类中的多个事件定义多个处理程序。您必须在方法前面加上“class {”,但您可以这样做。
C++ 没有匿名类或“实例”成员类。如果您有多个需要共享状态的处理程序,这使得为事件使用抽象类变得更加麻烦。您必须手动执行相当于生成闭包的操作,这很快就会变得非常烦人。
.NET 使用委托进行事件处理,这基本上是类型安全的函数指针。它们使处理事件的代码非常直接。然而,与 C++ 中的函数指针不同,委托统一了成员函数指针和静态函数指针。基本上它可以curry任何成员函数的“this”参数,留下一个看起来就像一个静态函数指针的函数指针。这意味着处理事件的对象类型不是事件“接口”的一部分。这使得它非常灵活。
您不能直接使用 C++ 成员函数指针来执行此操作,因为“this”类型最终成为函数指针类型的一部分,从而将处理程序限制为仅出现在当前类中。
C++ 的最佳解决方案是两者的混合。你想要的是一个像这样的通用接口:
class EventHandler
{
public:
virtual void Handle() = 0;
};
然后是这样的成员函数的实现
template <class T>
class MemberFuncEventHandler : public EventHandler
{
public:
MemberFuncEventHandler(T * pThis, void (T::*pFunc)()) : m_pThis(pThis), m_pFunc(pFunc)
{
}
void Handle()
{
(m_pThis->*m_pFunc)();
}
private:
T* m_pThis;
void (T::*m_pFunc)();
};
template <class T>
EventHandler * Handler(T * pThis, void (T::*pFunc)())
{
return new MemberFuncEventHandler<T>(pThis, pFunc);
}
您也可以类似地为静态方法定义一个处理程序类。然后你可以做这样的事情:
Handlers += Handler(obj, &(c1::foo));
Handlers += Handler(obj, &(c2::bar));
Handlers += Handler(blaa); // for static methods...