Intereting Posts

Как получить / расширить рекурсивный class

У меня есть рекурсивный class, своеобразное дерево, которое имеет экземпляры себя как переменные-члены. Например:

template class Tree { public: /* Constructors, etc. */ protected: T m_value; Tree *leftChild; Tree *rightChild; }; 

Если я хочу добавить метод, который печатает все значения, используя обход в порядке, я мог бы сделать это:

 template  void Tree::printInOrder() { leftChild->printInOrder(); std::cout << m_value <printInOrder(); } 

Но что, если по разным причинам я не мог или не хотел менять реализацию Tree? Если class не был рекурсивным, т. Е. Не содержал экземпляры самого себя, я мог бы просто получить из дерева и реализовать новый метод в производном classе. Но этот подход не работает для Tree.

 template  class DerivedClass : public Tree { public: void printInOrder(); } template  void DerivedClass:: printInOrder() { this->leftChild->printInOrder(); std::cout <m_value <rightChild->printInOrder(); } 

leftChild и rightChild являются экземплярами Tree и, следовательно, не имеют метода printInOrder ().

Может ли кто-нибудь предложить способ сделать это модульным способом без изменения реализации Tree. Это нормально изменить, как это реализовано в целом, если вам не нужно изменять его, когда вы хотите продлить / получить из classа. Я могу увидеть возможный способ сделать это, создав class T, чтобы методы делали то, что я хочу, но это просто кажется уродливым. Должен быть лучший способ.

Я очень доволен тем, что кто-то указывает, как я забыл что-то очевидное. Это, конечно, похоже на то, что у меня есть.

Изменить: Дело не в том, как реализовать printInOrder (). Это был просто пример. Дело в том, как получить class, чтобы дети также были производным classом.

Шаблон для типа узла.

 template class Tree { NodeType node; T m_data; }; template class Tree { struct Node { Tree* left; Tree* right; }; Node node; T m_data; }; template struct DerivedNode { DerivedTree* left; DerivedTree* right; }; template class DerivedTree : public Tree> { // now left and right are of type DerivedTree*. }; 

Это работает на основе двух инвариантов: Tree предлагает один и тот же интерфейс для всех NodeT и что DerivedTree наследует от Tree .

Редактировать: Черт, это потребовало больших усилий, чтобы предотвратить рекурсивное создание экземпляра Tree .

Сделайте printInOrder virtual функцией и сделайте ее доступной в Tree .

Это означает, что дерево chilren может быть произвольным потомком Tree и вызов printInOrder на них всегда будет ссылаться на переопределенную реализацию, если они предоставляют какой-либо.

Основной недостаток заключается в том, что все методы должны быть объявлены в Tree .

Если вы хотите неинтрузивную печать, просто укажите для нее простую функцию шаблона:

 template  void TreePrinter(const Tree& tree) { TreePrinter(tree.leftChild); std::cout << tree.m_value << std::endl; TreePrinter(tree.rightChild); } 

Вы, очевидно, нуждаетесь в TreePrinter в качестве друга:

 template class Tree { public: /* Constructors, etc. */ protected: T m_value; Tree *leftChild; Tree *rightChild; friend template  TreePrinter(const Tree&); }; 

В качестве альтернативы, если вы не должны иметь ее как друга, предоставляйте аксессурам, чтобы получить значение, а также левый и правый узлы дерева.

Это приемлемо для вас?

 template void DerivedClass::printInOrder() { ((DerivedClass*)leftChild)->printInOrder(); std::cout << this->m_value << std::endl; ((DerivedClass*)rightChild)->printInOrder(); } 

Вы можете просто написать функцию-член, которая возвращает экземпляр экземпляра:

 template  void DerivedClass::printInOrderHelper(const Tree& tree) { printInOrderHelper(tree->leftChild); std::cout << tree->m_value << std::endl; printInOrderHelper(tree->rightChild); } 

Используйте это при перегрузке с нулевым параметром:

 template  void DerivedClass::printInOrder() { printInOrderHelper(*this); }