我试图了解C ++中的模板是如何工作的,所以我想用C ++模板实现一个树。这是一个传统的多态版本:
#include <iostream>
using namespace std;
class Node {
public:
virtual ~Node() {}
virtual void print() = 0;
};
class InnerNode : public Node {
public:
InnerNode(Node *lhs, Node *rhs) {
m_lhs = lhs;
m_rhs = rhs;
}
virtual ~InnerNode() {
delete m_lhs;
delete m_rhs;
}
virtual void print() {
cout << "inner" << endl;
if (m_lhs != NULL)
m_lhs->print();
if (m_rhs != NULL)
m_rhs->print();
}
private:
Node *m_lhs;
Node *m_rhs;
};
class LeafNode : public Node {
virtual void print() {
cout << "leaf" << endl;
}
};
int main() {
Node *l1 = new LeafNode();
Node *l2 = new LeafNode();
Node *r = new InnerNode(l1, l2);
r->print();
}
我正在尝试仅使用模板来实现此代码的版本,但我遇到了类似这样的问题:
#include <iostream>
using namespace std;
template <typename T>
class Node {
public:
virtual ~Node() {}
void print() {
static_cast<T *>(this)->print();
}
};
class InnerNode : public Node<InnerNode> {
public:
InnerNode(Node *lhs, Node *rhs) {
m_lhs = lhs;
m_rhs = rhs;
}
virtual ~InnerNode() {
delete m_lhs;
delete m_rhs;
}
void print() {
cout << "inner" << endl;
if (m_lhs != NULL)
m_lhs->print();
if (m_rhs != NULL)
m_rhs->print();
}
private:
Node *m_lhs;
Node *m_rhs;
};
class LeafNode : public Node<LeafNode> {
virtual void print() {
cout << "leaf" << endl;
}
};
int main() {
Node *l1 = new LeafNode();
Node *l2 = new LeafNode();
Node *r = new InnerNode(l1, l2);
r->print();
}
如何调整多态版本以改为使用模板?
答案 0 :(得分:1)
模板允许您使用名称替换类型,并使用该类型生成代码的特定实例。例如,可以使用变量类型的节点。
您的节点&lt;&gt;模板永远不会引用模板类型参数,因此没有理由将其作为模板。本质上你的节点&#34; class只是一个抽象的接口,而不是一个模板。 InnerNode也不需要是一个模板,因为没有不同的类型,因为你只需要将基类指针存储到叶子。
叶子具有数据,因此是被模板化的候选者,但是由于您的示例在叶子节点中没有数据,因此模板类型的应用不明显。
希望这能说明:
#include <iostream>
using namespace std;
// interface for interacting with general nodes
class INode {
public:
virtual ~INode() {}
virtual void print() = 0;
};
class InnerNode : public INode {
public:
InnerNode(INode *lhs, INode *rhs) {
m_lhs = lhs;
m_rhs = rhs;
}
virtual ~InnerNode() {
delete m_lhs;
delete m_rhs;
}
void print() {
cout << "inner" << endl;
if (m_lhs != NULL)
m_lhs->print();
if (m_rhs != NULL)
m_rhs->print();
}
private:
INode *m_lhs;
INode *m_rhs;
};
template< typename DataType >
class LeafNode : public INode {
virtual ~LeafNode() {};
public:
LeafNode(DataType data) : m_data(data) {}
virtual void print() {
cout << "leaf:" << endl;
cout << m_data << endl;
}
private:
DataType m_data;
};
int main() {
INode *l1 = new LeafNode<int>(2);
INode *l2 = new LeafNode<float>(3.14);
INode *r = new InnerNode(l1, l2);
r->print();
delete r;
}
答案 1 :(得分:-2)
您的问题预先假定树是保存数据的数据结构。该数据是模板将处理的类型。如果您没有任何数据,那么您没有一个数据类型来概括(模板)。
由于您询问了模板,我假设您有一棵树,它跟踪“某些数据类型”,我们将其称为myDataType。假设它是一个字符串。这是一个绝对最小的树接口,没有任何实现细节。我知道这是一个非常无用的树,但问题是模板。
typedef myData std::string;
class tree {
private:
struct node {
myData data;
node * left, right;
};
node * head;
public:
void add (myData value);
bool is_value_in_the_tree (const myData &value);
};
如果为内部和叶子节点使用不同的节点类型,那没问题。这是写一棵树的一部分。实施细节。我不在乎。只要树适用于一种数据类型,转到模板就可以使其适用于任何数据类型。 (1)
所有努力工作都是为了实际制作树。转到模板,以便它可以使用任何数据类型,而不仅仅是“myData”很容易。只需说模板&lt; typename myData&gt;这样你就可以使用不同的类型,而不需要typedef,它只能是一种类型。或者,像其他人一样使用“T”:
template<typename T>
class tree {
private:
template<typename T>
struct node {
T data;
node<T> * left, right;
};
node<T> * head;
public:
void add(T value);
bool is_value_in_the_tree(const T &value);
};
请注意,由于树和节点现在是模板,因此您必须指定使用它们时的类型,尽管它可以是不同树的不同类型。树将是一棵树。
tree<std::string> t;
assert(!t.is_value_in_the_tree("hello");
t.add("hello")
assert(t.is_value_in_the_tree("hello");
另请注意,节点是私有的,并使用相同的T.您不必将它们设为私有,但我会这样做。但是让它们使用相同的类型是至关重要的,因为如果有人声明树,节点将处理某种类型。
注意1:好的,显然树不适用于任何类型,但是如果类型缺少树所需的类型,如运算符&lt;()或某些节点构造函数,则会出现链接器错误,具体取决于关于如何实现树。