我正在编写一个Window
传播不同类型事件的类,列在
enum Event {WINDOW_ClOSE=0x1, WINDOW_REDRAW=0x2, MOUSE_MOVE=0x4, ...};
到已注册通知窗口的对象。对于每种类型的事件,我都有一个抽象类,任何对象都必须扩展它以允许通知。为了对一个事件做出反应MOUSE_MOVE
,我的对象将继承自MouseMoveListener
,它有一个process_mouse_move_event()
由 调用的方法Window
。可以通过扩展这些类中的多个来组合侦听许多事件,这些类都继承自基EventListener
类。要注册一个对象,我会调用
void Window::register(EventListener* object, int EventTypes)
{
if(EventTypes&WINDOW_CLOSE)
/* dynamic_cast object to WindowCloseListener*, add to internal list of all
WindowCloseListeners if the cast works, else raise error */
if(EventTypes&MOUSE_MOVE)
/* dynamic_cast object to MouseMoveListener*, add to internal list of all
MouseMoveListeners if the cast works, else raise error */
...
}
这很好用,但我的抱怨是它EventListener
完全是空的,而且我觉得代码很臭。我知道我可以通过EventListener
完全删除并为每种类型的事件单独设置来避免这种Window::register
情况,但我觉得这会不必要地炸毁我的界面(特别是因为其他方法register
可能会出现同样的问题)。所以我想我正在寻找答案,要么说:
“你可以按照你的方式继续做,因为......”或
“无论如何都要引入单独的
Window::register
方法,因为......”或者当然“你做错了,你应该……”。
编辑:
来自 Igors 评论中的链接:我上面所做的只有在至少有一个虚拟成员( EventListener
例如虚拟析构函数)时才有效,因此该类在技术上并非完全为空。
编辑2:
我过早地接受了 nm 的解决方案作为“我做错了”的类型之一。但是,它属于第二种。即使我可以EventListener->register(Window&)
多态调用,也Window
需要实现一个高度冗余的接口(就声明的方法而言),它允许EventListeners
注册选择性通知。这等效于我上面描述的替代解决方案,只是EventListener
无缘无故地额外引入了该类。总之,规范的答案似乎是:
不要dynamic_cast
为了避免声明许多类似的函数而做+空基类,这会在以后维护代码时伤害您。编写许多函数。
编辑 3:
我找到了一个令我满意的解决方案(使用模板)。它不再使用空基类,也没有出现 nm 指出的维护问题