c++ - 从基指针列表循环 (OOD) 调用派生类方法

标签 c++ oop inheritance design-patterns polymorphism

问题

我遇到了一个简单的问题,但我无法为它想出一个合适的 OOD。

我有什么:

  • 基类
  • 子类添加新方法 foo()
  • 指向基类实例的指针列表

我需要什么:

我需要遍历此列表并为支持此方法的对象调用 foo(),即上述子类的(或派生的)对象。或者一般来说,我需要通过指向基类的指针列表对子类进行“无异味”的多态访问。

示例代码

class Entity {
    // ...
    // This class contains methods also needed by subclasses.
};

class SaveableEntity : public Entity {
public:
    virtual void save() = 0;
};

// SaveableEntity has multiple subclasses with specific save() implementations.

std::vector<Entity *> list;
for (Entity *entity : list) {
    // Here I need to save() the descendants of a SaveableEntity type.
}

我想出了一些想法,但我觉得没有一个是对的。以下是其中一些:

方法一:dynamic_cast

由于有些元素是可保存的,有些元素不是,我看到的最明显的方法是动态转换:

std::vector<Entity *> list;
for (Entity *entity : list) {
    auto saveable = dynamic_cast<SaveableEntity *>(entity);
    if (saveable) {
        saveable->save();
    }
}

但是,在这种情况下使用 dynamic_cast 看起来像是一个糟糕的 OOD(如果我错了请纠正我)。此外,这种方法很容易导致违反LSP。 .

方法二:将save()移到基类

我可以删除 SaveableEntity 并将 save() 方法移动到基础 Entity。然而,这让我们实现了虚拟方法:

class Entity {
    virtual void save() {
        // Do nothing, override in subclasses
    }
};

这消除了 dynamic_cast 的用法,但虚拟方法似乎仍然不正确:现在基类保存的信息(save() 方法)与

方法三:应用设计模式

  • Strategy 模式:SaveStrategy 类及其子类,如 NoSaveStrategySomeSaveStrategySomeOtherSaveStrategy 等。再次,NoSaveStrategy 的存在让我们回到了先前方法的缺陷:基类必须知道其子类的特定细节,这似乎是一个糟糕的设计。<
  • ProxyDecorator 模式可以很容易地封装dynamic_cast,但是这只会隐藏不需要的代码,并不能摆脱糟糕的设计本身。
  • 添加一些 composition-over-inheritance 层,等等......

问题

也许我遗漏了一些明显的解决方案,或者所描述的方法(1 或 2)在这个特定的上下文中并不像我看到的那样糟糕和难闻。

那么在这种情况下应该采用什么样的设计方法呢?

最佳答案

有面向数据编程鼓励的解决方案 #4(在 2018 年 cppcon 上有一个很好的演讲,可在 youtube 上找到):有两个列表。一个列表用于所有 SavableEntity,另一个用于不可保存的 Entity

现在,您遍历第一个列表并 ->save() 这些项目。

主要优点是您只迭代相关实体。通过一些(可能是主要的)重构,您可以拥有对象的集合而不是指向某些对象的指针。这将增加数据局部性并显着减少缓存未命中的次数。

关于c++ - 从基指针列表循环 (OOD) 调用派生类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53433458/

相关文章:

c++ - 我可以直接为指针分配地址吗?如果是这样,该怎么做?

c++ - 固定值的模板特化

oop - 如何模拟依赖于基础物质的措施

java - 在父 Java 类中注入(inject)样板代码

c++ - 继承中的析构函数

c++ - 需要在后代 .h 文件中重新声明被覆盖的函数

c# - 在继承类中隐藏/重载辅助方法时基类方法的行为

c++ - 非标量类型子类错误

c++ - 我们什么时候应该将代码封装为 "Class"?

C++ : wxWidget HelloWorld