如何派生/扩展递归类

发布于 2024-11-16 11:23:46 字数 1250 浏览 5 评论 0原文

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

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()。这只是一个例子。重点是如何派生一个类,使子类也是派生类。

I have a recursive class, a kind of tree, that has instances of itself as member variables. For example:

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

If I want to add a method that prints all the values using an in-order traversal, I could do this:

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

But what if, for various reasons, I couldn't or didn't want to change Tree's implementation? If the class wasn't recursive, i.e. didn't contain instances of itself, I could just derive from Tree and implement a new method in the derived class. But this approach doesn't work for 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 and rightChild are instances of Tree and thus don't have a printInOrder() method.

Can anyone suggest a way to do this in a modular way without changing Tree's implementation. It's ok to change how it is implemented in general, as long as you don't have to change it whenever you want to extend/derive from the class. I can see a possible way to do it by making the template class T have methods to do the things I want, but that just seems ugly. There must be a better way.

I'm perfectly happy for someone to point out how I've overlooked something obvious. It certainly feels like I have.

Edit: The point is not how to implement printInOrder(). That was just an example. The point is how to derive a class so that the children are also the derived class.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

唐婉 2024-11-23 11:23:46

节点类型上的模板。

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 为所有 NodeT 提供相同的接口,并且 DerivedTree 继承来自 Tree

编辑:该死,花了很多精力来防止 Tree的递归实例化。

Template on the node type.

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>*.
};

This works based on two invariants- that Tree<T, NodeT> offers the same interface for all NodeT, and that DerivedTree<T> inherits from Tree<T, ...>.

Edit: Damn, that took a lot of effort to prevent recursive instantiation of Tree<T, NodeType>.

帥小哥 2024-11-23 11:23:46

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

这意味着树子级可以是 Tree 的任意后代,并且对它们调用 printInOrder 将始终调用重写的实现(如果它们提供了任何实现)。

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

Make printInOrder a virtual function and make it available in Tree.

This means tree chilren can be arbitrary descendents of Tree and calling printInOrder on them will always invoke the overriden implementation, if they provide any.

The major downside is that all methods need to be declared in Tree.

梦里°也失望 2024-11-23 11:23:46

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

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>&);
};

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

If you want non-intrusive printing, just specify a plain template function for it:

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

You obviously need a TreePrinter as a friend though:

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>&);
};

Alternatively if you don't to have it as a friend, provide accessors to get the value as well as the left and right nodes of the tree.

梦年海沫深 2024-11-23 11:23:46

您可以接受吗?

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

Is it acceptable for you?

template <class T>void DerivedClass<T>::printInOrder()
{   
    ((DerivedClass<T>*)leftChild)->printInOrder();   
    std::cout << this->m_value << std::endl;   
    ((DerivedClass<T>*)rightChild)->printInOrder();
}
痴骨ら 2024-11-23 11:23:46

您可以简单地编写一个接受实例进行打印的成员函数:

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);
}

You can simply write a member function that takes the instance to print:

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

Use this in a zero-parameter overload:

template <class T>
void DerivedClass::printInOrder()
{
    printInOrderHelper(*this);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文