C ++:树根是否应在结构上使用继承?

时间:2019-04-21 21:18:44

标签: c++ inheritance tree composition

我有一个像这样的树状数据结构:

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. 我也可以在Tree上调用Root上定义的所有递归函数,而不必将其复制粘贴。
  2. 根拥有该存储,因此只要它超出范围,这就是我将树定义为不再有效的方式。

但是后来我意识到了一个问题。有人可能会不经意间打电话给

Tree *root = new Root();

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

这不是预期的用法(任何普通用法都应在堆栈上使用Root)。但是我愿意接受其他选择。现在,要解决此问题,我有三个建议:

  • 将虚拟析构函数添加到Tree。由于树的开销,我宁愿不这样做,因为树可以有很多很多节点。
  • 不要让Root继承自Tree,而要让它定义自己的Tree成员。创建一点间接性(不是太可怕),仍然可以通过执行Tree来调用root.tree().recursive()中大量有用的递归函数。
  • 禁止分配诸如Tree *root = new Root();之类的作业。我什至不知道这是否可能,不鼓励或鼓励。有编译器构造吗?
  • 还有什么?

我应该选择其中哪一个?非常感谢你!

1 个答案:

答案 0 :(得分:0)

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

  

禁止使用类似Tree *root = new Root();之类的作业。我什至不知道这是否可能,不鼓励或鼓励。有编译器构造吗?

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