【问题标题】:C++: Should a tree root use inheritance over composition?C ++:树根是否应该使用继承而不是组合?
【发布时间】:2019-04-21 21:18:44
【问题描述】:

我有一个类似树的数据结构,我这样设置:

class Root; // forward declaration

class Tree {
public:
    void addChildren(Root &r, ...) { childA = r.nodeSpace.allocate(); ... }
    // tons of useful recursive functions here
private:
    Tree *childA, *childB, *childC;
    Tree *parent;
    int usefulInt;
};

class Root : public Tree {
    friend class Tree; // so it can access our storage
public:

private:
    MemoryPool<Tree> nodeSpace;
};

我真的很喜欢这种结构,因为

  1. 我也可以在Root 上调用Tree 上定义的所有递归函数,而无需复制粘贴它们。
  2. Root 拥有存储空间,因此每当它超出范围时,这就是我将树定义为不再有效的方式。

但后来我意识到一个问题。有人可能会不小心打来电话

Tree *root = new Root();

delete root; // memory leak! Tree has no virtual destructor...

这不是预期的用法(任何普通用法都应该在堆栈上有Root)。但我对替代品持开放态度。现在,为了解决这个问题,我有三个建议:

  • 将虚拟析构函数添加到Tree。我宁愿不这样做,因为树可以有很多很多节点。
  • 不要让Root 继承自Tree,而是让它定义自己的Tree 成员。创建一个小间接,不是太糟糕,仍然可以通过 root.tree().recursive() 调用 Tree 中大量有用的递归函数。
  • 禁止分配Tree *root = new Root();。我不知道这是否可能或不鼓励或鼓励。有编译器构造吗?
  • 还有别的吗?

我应该更喜欢哪一个?非常感谢!

【问题讨论】:

标签: c++ inheritance tree composition


【解决方案1】:

根节点类(或任何其他节点类)不应是接口类。保留它private,然后在没有动态多态性的情况下继承 (virtual) 并不危险,因为用户永远不会看到它。

禁止分配Tree *root = new Root();。我不知道这是否可能或不鼓励或鼓励。有编译器构造吗?

这可以通过将Root 继承自Tree 作为私有基类来实现。

【讨论】:

  • 谢谢!恐怕我很困惑。我应该保留什么private:你的意思是class Root : private Tree
  • 我的第一个建议是将RootNode 都作为隐藏的实现细节,并定义其他类来处理接口。然后我指出class Root : private Tree 是朝着您提到的另一个方向更简单的解决方案。
  • 我明白了,谢谢!我在一些随机网站上读到“私有继承意味着在-条款中实现。它通常不如组合”。你会建议使用上面的组合提案而不是私有继承选项吗?
  • @bombax 您可以在便利性与质量等级的几个步骤中进行选择。最好的质量是定义一组用于实现/内存存储的类,并对用户隐藏它们,以及另一组用于接口/数据访问的类。最好的方便就是方便。构图是在质量方向上迈出的一大步,但只是一小步。
猜你喜欢
  • 2018-06-01
  • 1970-01-01
  • 2015-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多