我正在写一个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:
我过早接受n.m.的解决方案,将其作为“我做错了所有事情”之一。但是,它是第二种类型。即使我可以多态调用
EventListener->register(Window&)
,Window
也需要实现一个高度冗余的接口(就已声明的方法而言),该接口允许EventListeners
注册进行选择性通知。这等效于上述我的替代解决方案,只是没有充分的理由附加了EventListener
类。总之,规范的答案似乎是:不要做
dynamic_cast
+空基类只是为了避免声明许多类似的函数,否则在以后维护代码时会伤害您。编写许多功能。编辑3:
我找到了一个对我来说令人满意的解决方案(使用模板)。它不再使用空的基类,也不会出现n.m指出的维护问题。
最佳答案
object->registerWindow (this, EventTypes);
当然,您需要为所有
registerWindow
继承人实现EventListener
。让他们检查与他们相关的事件类型。更新
如果这意味着您需要重新设计代码,则需要重新设计代码。为什么会这样呢?因为
dynamic_cast
不是执行接通类型的正确方法。这不是正确的方法,因为每次在层次结构中添加类时,都需要遍历并可能更新旧代码中的所有动态转换开关。这变得非常混乱,并且很快无法维护,这正是发明虚拟功能的原因。如果您使用虚拟功能进行接通类型,则每次更改层次结构时,您都不需要执行任何操作。虚拟呼叫机制将负责您的更改。
关于c++ - 在此示例中使用空基类是合理的吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19411053/