c++ - 在此示例中使用空基类是否合理?

标签 c++ inheritance base-class

我正在编写一个 Window 类,它传播不同类型的事件,列在

enum Event {WINDOW_ClOSE=0x1, WINDOW_REDRAW=0x2, MOUSE_MOVE=0x4, ...}; 

已注册窗口通知的对象。对于每种类型的事件,我都有一个抽象类,任何对象都必须扩展该抽象类才能允许通知。例如,为了响应 MOUSE_MOVE 事件,我的对象将从 MouseMoveListener 继承,它有一个 process_mouse_move_event() 方法,该方法由 窗口。可以通过扩展这些类中的多个来组合监听多个事件,这些类都继承自 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 也需要实现一个高度冗余的接口(interface)(就声明的方法而言),它允许 EventListeners 注册选择性通知。这等同于我上面描述的替代解决方案,只是无缘无故地额外引入了 EventListener 类。总之,规范的答案似乎是:

不要为了避免声明很多类似的函数而做dynamic_cast + 空基类,这会在以后维护代码时伤害到你。编写许多函数。

编辑 3:

我找到了一个令我满意的解决方案(使用模板)。它不再使用空基类,也不会出现 n.m. 指出的维护问题。

最佳答案

object->registerWindow (this, EventTypes);

当然你需要为所有的EventListener继承者实现registerWindow。让他们检查与他们相关的事件类型。

更新

如果这意味着您需要重新设计代码,那么您需要重新设计代码。为什么会这样?因为 dynamic_cast 不是执行类型切换的正确方法。这不是一种正确的方法,因为每次在层次结构中添加一个类时,您都需要遍历并可能更新旧代码中的所有 switches-by-dynamic-cast。这很快就会变得非常困惑和难以维护,这正是虚函数被发明的原因。

如果您使用虚函数执行开关类型,则每次更改层次结构时都必须...什么都不做。虚拟调用机制将处理您的更改。

关于c++ - 在此示例中使用空基类是否合理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19411053/

相关文章:

java - 我可以为每种不同类型的继承类拥有不同的静态变量副本吗

c++ - 基类构造函数错误

inheritance - VB6在子类中访问父类的重载接口(interface)子程序

c++ - 高斯约尔消元法

c++ - 在 gdb/Ubuntu 14.04.4 LTS 中加载 dl-debug.c

c++ - 引用类模板参数和 constexpr 类成员的转换运算符

c++ - 指向基本类型的指针的 vector ,找到存储在基本类型中的给定派生类型的所有实例

c++ - C++ 编译错误消息中的 __tpdsc__ 是什么意思?

javascript - 如何从基础对象继承函数并在javascript中覆盖它

php - 在 PHP 中是否有动态扩展类的选项?