C++模板类指针声明

28
template <typename T>
class Node
{...};

int main
{
    Node* ptr;
    ptr = new Node<int>;
}

如果我没声明指针,编译会失败。

Node<int>* ptr;

为什么在声明尚未创建的类的指针时必须指定类型,编译器为什么需要知道它将要指向哪种类型。是否不可能创建一个通用指针,之后再决定要分配哪种类型。


23
到目前为止还没有出现过这个答案,我认为它不值得被写下来,但这里有一个重要的细节:Node 不是一种类型,而是一个模板。虽然它确实是一个模板,但只有像 Node<int>Node<double>Node<Node<void> > 这样的东西才是类型; Node 将永远是一个模板,并且只有指向类型的指针,不存在指向模板的指针。 - Luc Danton
7
这一点非常重要,它应该放在回答中而不仅仅是评论中。 - David Hammen
正确的语法不应该是 Node<int>* ptr = new Node<int>(); 吗?我认为应该加上 () - enthusiasticgeek
@enthusiasticgeek 这是可选的。 - user6455909
5个回答

40

模板在编译时解析类型。当您将新的Node<int>对象分配给它时,指针必须在编译时确切地知道它是什么类型。

Node<int>Node<std::vector>在二进制文件中可能非常不同(根据模板参数,对象的二进制布局会完全改变),因此将未解析的指针类型指向模板没有任何意义。

您应该先为节点定义一个公共父类:

class NodeBase
{ ... }

template<typename ValueT>
  class Node : public NodeBase
{
 ...
};

NodeBase* ptr;

@Mike,你成功地重写了我的完整答案。你确定这是你的意图吗? - progician
8
我所做的就是在 Node<int>Node<std::vector> 周围加上反引号,以将它们格式化为代码而不是文本。如果没有这种格式化,该句话读作“Node和Node可能非常不同”,这没有意义。 - Mike Seymour
4
@Yola,我不太确定你在这里的意思是什么?问题并没有涉及虚函数调用带来的开销。在某些情况下,虚函数是唯一的选择,即在运行时解析函数时。 - progician

11
简单来说,这是因为C++使用了(相当)严格的静态类型检查机制。Node<int>Node<double> 是完全不同的类型,当编译器看到ptr->doSomething()时,必须确定是调用Node<int>::doSomething() 还是Node<double>::doSomething()
如果确实需要一些动态通用性,即只有在运行时才能知道指针ptr所指向的实际类型,您需要定义一个基类,并从其中派生出子类。(这是一种相当常见的模式,即类模板派生自非模板基类,以便于指针的通用性可以在运行时解析。)

5
为什么在声明指针时必须指定类型,即使我还没有创建该类,为什么编译器也必须知道它将指向哪种类型。
指针有许多用途,以下是其中的几个例子:
- 基于指针类型调用多个函数 - 从中索引(假设它指向连续数组中的第一个元素) - 获取指向对象的大小 - 将其传递给模板,其中指针类型是参数
为了使编译器能够有效地生成执行这些操作的代码,它需要知道指针的类型。如果它推迟决策直到看到指针的类型,那么它需要:
- 为指针可能采用的每种类型编译高效的代码(使程序变得非常臃肿),或者 - 创建无法处理所有可能类型的低效代码,通过一些最坏情况下的悲观笨拙行为,或者 - 将自己(编译器)嵌入到C++程序中,以便在获得必要信息时完成工作 - 这将使每个微不足道的程序变得巨大(和缓慢)
是否不能创建通用指针,然后在之后决定要分配哪种类型?
有点像...你有很多选择:
- 使用void*,但在可以对指向的类型再次进行有意义的操作之前,您需要手动将其强制转换回该类型:在您的情况下,这意味着在记录它是什么之后,还需要为每种可能性编写单独的代码 - 使用boost::any<> - 基本上像一个void*,但具有内置的安全性 - 使用boost::variant<> - 更安全、更方便,但创建指针时必须列出可能的指向类型 - 使用运行时多态对象和虚拟调度...这是经典的面向对象编程...您有一个指向“抽象”节点的指针,该节点声明了用于操作任何特定类型的节点所使用的共享函数和成员数据,然后模板化的Node类从该抽象Node继承并实现了函数的类型特定版本。然后通过指向基类的指针使用虚拟函数调用这些函数。

1
无论何时您在C++中创建任何类型的对象(包括指针),都必须知道对象的完整类型。在您的代码中没有Node这样的类型,因此您无法创建指向它的指针实例。您需要重新考虑如何设计和编写您的代码。

1
正如Neil Butterworth和Luc Danton所指出的那样,您不能有一个类型为Node*的指针,因为Node不是一种类型,而是一个模板。是的,Node是一个类模板,但是这里的class只是限定了模板的种类。一种看待它的方式是:就像类和类的实例非常不同一样,模板和模板实例化也是如此。那些模板实例化,例如Node,才是类。类模板是另一种类型的东西。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接