如何派生/扩展递归类

时间:2011-06-20 20:09:51

标签: c++ inheritance recursion derived-class

我有一个递归类,一种树,它有自己的实例作为成员变量。例如:

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

如果我想添加一个使用有序遍历打印所有值的方法,我可以这样做:

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

但是,如果出于各种原因,我不能或不想改变Tree的实现呢?如果类不是递归的,即不包含它自己的实例,我可以从Tree派生并在派生类中实现一个新方法。但这种方法对Tree不起作用。

template <class T>
class DerivedClass : public Tree<T> {
public:
  void printInOrder();
}

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

leftChild和rightChild是Tree的实例,因此没有printInOrder()方法。

任何人都可以建议一种方法,以模块化方式执行此操作,而无需更改Tree的实现。只要您不想在每次扩展/派生时更改它,就可以改变它的实现方式。我可以看到一种可能的方法,通过使模板类T有方法来做我想要的东西,但这看起来很难看。必须有更好的方法。

我很高兴有人指出我是如何忽略了一些显而易见的事情。它当然感觉像我一样。

编辑:关键不在于如何实现printInOrder()。那只是一个例子。关键是如何派生一个类,以便孩子们也是派生类。

5 个答案:

答案 0 :(得分:1)

节点类型上的模板。

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

这基于两个不变量 - Tree<T, NodeT>为所有NodeT提供相同的界面,而DerivedTree<T>继承自Tree<T, ...>

编辑:该死的,为了防止Tree<T, NodeType>的递归实例化而花费了很多精力。

答案 1 :(得分:0)

使printInOrder成为virtual函数,并在Tree中使其可用。

这意味着,chilren可以是Tree的任意后代,如果它们提供任何后代,则调用printInOrder将始终调用覆盖实现。

主要缺点是所有方法都需要在Tree中声明。

答案 2 :(得分:0)

您只需编写一个将实例打印的成员函数:

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

在零参数过载中使用它:

template <class T>
void DerivedClass::printInOrder()
{
    printInOrderHelper(*this);
}

答案 3 :(得分:0)

如果您想要非侵入式打印,只需为它指定一个普通的模板函数:

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

你显然需要一个TreePrinter作为朋友:

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

  friend template <typename U>
  TreePrinter(const Tree<U>&);
};

或者,如果您不将其作为朋友,请提供访问者以获取值以及树的左右节点。

答案 4 :(得分:0)

你能接受吗?

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