C ++: должен ли корень дерева использовать наследование над композицией? - PullRequest
0 голосов
/ 22 апреля 2019

У меня есть древовидная структура данных, которую я настроил так:

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. Root владеет хранилищем, поэтому всякий раз, когда оно выходит из области видимости, именно так я определяю дерево какдольше действителен.

Но потом я понял проблему.Кто-то может случайно вызвать

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 голосов
/ 22 апреля 2019

Класс корневого узла (или любой другой класс узла) не должен быть интерфейсным классом.Сохраняйте его private, и тогда наследование без динамического полиморфизма (virtual) не опасно, поскольку пользователь никогда его не увидит.

Запрещает присваивания, такие как Tree *root = new Root();.Я понятия не имею, возможно ли это или обескуражено или поощрено.Существуют ли конструкции компилятора?

Это можно сделать, если Root наследовать от Tree в качестве частного базового класса.

...