【问题标题】:Getting error because of template in Tree class由于 Tree 类中的模板而出现错误
【发布时间】:2020-03-03 09:24:03
【问题描述】:

我有一个 Tree 类,在这个类中我有一个私有的 Node 类(嵌套)。 Tree 类当然是一个模板类。
问题是,当我想将一个树子插入到一个没有确切子代数的树父代中时,我收到一个类型不兼容的错误以进行转换。


这是我的代码:
tree.hpp

#ifndef TREE_HPP
#define TREE_HPP

#include <iostream>
#include <cstddef> 

template <typename T, char N>
class Tree {
private:
  class Node;
  Node* _info;
public:
  Tree();
  Tree(T, char);
  Tree(const Tree&) = delete;  // copy constructor
  Tree& operator= (const Tree&) = delete; // assignement by copy constructor
  Tree (Tree&&); // transfer constructor
  Tree& operator= (Tree&&); // assignement by transfer constructor
  ~Tree() {delete _info;}
  bool ins(char, Tree&);
  Tree* fils(char);
};

template <typename T, char N>
Tree<T, N>::Tree() 
  : _info(nullptr) {}

template <typename T, char N>
Tree<T, N>::Tree(T data, char size) {
  Node* node = new Node(data);
  _info = node;
}

template <typename T, char N>
Tree<T, N>::Tree(Tree&& t) {
  _info = t._info;
  t._info = nullptr;
}

template <typename T, char N>
Tree<T, N>& Tree<T, N>::operator= (Tree&& t) {
  if (&t != this) {delete _info; _info = t._info; t._info = nullptr;}
  return *this;
}

template <typename T, char N>
bool Tree<T, N>::ins(char index, Tree& childTree){
  if (_info){
    _info->getChildren()[index] = &childTree;
    return true;
  }
  return false;
}

template <typename T, char N>
Tree<T,N>* Tree<T, N>::fils(char index){
  return _info->getChildren()[index];
}

template <typename T, char N>
class Tree<T, N>::Node {
private:
  T _data;
  Tree* _children[N];
  bool _isWord;
public:
  Node();
  Node(T);
  Tree** getChildren() {return this->_children;}
  T getData(){return this->_data;}
  ~Node() = default;
};

template <typename T, char N> // Node class default constructor
Tree<T,N>::Node::Node(){
  _data = 0;
  _children = nullptr;
  _isWord = false;
}

template <typename T, char N> // Node class constructor
Tree<T,N>::Node::Node(T data){
  _data = data;
  _isWord = false;
  for (char i = 0; i < N; i++) 
    _children[i] = NULL;
}

#endif

ma​​in.cpp

#include <iostream>
#include <cstddef>
#include "tree.hpp"

#define SIZE 5
#define display(x) std::cout<<x<<std::endl
int main() {
  Tree<char,SIZE> n1('A',SIZE);
  Tree<char,SIZE> n1_1('B',SIZE); // works fine
  Tree<char,10> n1_2('C',10); // sends the error
  n1.ins(0,n1_1);
  n1.ins(1,n1_2);
  return 0;
}

错误是:

main.cpp: In function ‘int main()’:
main.cpp:16:12: error: cannot convert ‘Tree<char, '\012'>’ to ‘Tree<char, '\005'>&’
   16 |   n1.ins(1,n1_2);
      |            ^~~~
      |            |
      |            Tree<char, '\012'>
In file included from main.cpp:4:
tree.hpp:80:40: note:   initializing argument 2 of ‘bool Tree<T, N>::ins(char, Tree<T, N>&) [with T = char; char N = '\005']’
   80 | bool Tree<T, N>::ins(char index, Tree& childTree){
      | 

我也愿意接受有关改进此代码的方法的建议。
谢谢...

【问题讨论】:

  • N 的变化意味着类是不同的类型。当您显然不想要固定数量的孩子时,我看不到您从拥有固定数量的孩子中得到什么。我会删除模板N 并动态分配孩子的数量。如果允许,请使用std::vector
  • 为了完整起见,您应该将Node 的定义添加到问题中。旁注:看看你是否可以对用户隐藏Node,绝对不要让他们引用一个。当用户意外释放或损坏节点时,它会很糟糕,因为它破坏了整个数据结构。
  • @user4581301 我不太明白你在说什么,但是当我想使用 Node 对象时,我可以向 Node 发送一个 const 引用,而这种情况下我不修改 node,因为它是 const。
  • 假设:Node 包含一个大小为N 的子节点数组。这意味着Node&lt;5&gt;Node&lt;10&gt; 的大小不同,并且不再兼容。您可以做的是创建一个非模板化的Base_Node 类,Node 继承自该类。 Base_Node 声明了Node 的所有功能,但没有实现它们。 Tree 存储并看到指向 Base_Node 的指针,并且不知道有多少孩子,因此实际上指向的是什么类型的 Node。这解决了兼容性问题,但让Tree 很难确定要构造哪个Node
  • 以上将动态分配的数量保持在最低限度,但不能很好地扩展。

标签: c++ templates tree insertion


【解决方案1】:

Tree 类当然是一个模板类。

树不一定是模板。不要“仅仅因为”做事;)。

Tree&lt;char,10&gt;Tree&lt;char,5&gt; 是两种不同的类型。除非您实施某种方法来转换它们,否则您无法将它们转换为另一种。

目前尚不清楚,为什么您决定将树中子节点的数量作为树类型的一部分。添加或删除子节点会生成不同类型的树。

考虑 std::arraystd::vectorstd::array 有元素数量作为模板参数,因为它的大小永远不会改变。另一方面,std::vector 具有动态大小。

实际上我不明白为什么您的Tree 需要知道其节点children 数组的大小。要么我错过了它,要么你从不在Tree 中使用N。我没有遵循所有细节,但您似乎可以安全地从代码中完全删除 N 并为节点子节点使用 std::vector

【讨论】:

  • 感谢您的回答。在这里我确实需要使用模板,因为我不知道将传递给我的树的类型。虽然我确信最好删除 N 并使用 std::vector。
  • @Mohammadreza 我不想建议不要使用模板。 “我不知道将传递给我的树的类型”是编写模板的好理由,但您没有充分的理由在N上对模板进行参数化@
  • 是的,我同意。我将删除 N 并改用 std::vector
  • 但是我想知道我是否可以选择我的向量的索引并将其分配给某些东西?或者不可能做这样的事情,我被push_back()卡住了
【解决方案2】:

为什么不使用 std::vector 并且只将 N 作为参数传递给节点?然后在节点中创建一个插入函数来检查是否未达到最大大小

【讨论】:

  • 我不喜欢使用 std::vector 但我喜欢你将 N 作为参数传递的想法。我也知道,std::vector 是在堆还是栈上分配向量?
  • @Mohammadreza vector 动态分配。堆是动态存储的常见实现。 Documentation for std::vector
  • 您可以在向量上使用 at 函数来获取元素的引用来更改它。但是您需要检查向量的大小是否优于您要访问的元素
【解决方案3】:

当 c++ 创建一个对象时,它会静态创建它,这意味着 SIZE 4 的对象与 SIZE 5 的对象完全不同。这两个对象完全不同,你不能像对待他们一样对待它们

p>

【讨论】:

  • 谢谢。我现在明白该怎么做了。我删除 N 并将 std::vector 用于我的_children
猜你喜欢
  • 2021-05-29
  • 1970-01-01
  • 2019-11-21
  • 2015-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-06
  • 1970-01-01
相关资源
最近更新 更多