【问题标题】:Template class pointer c++ declaration模板类指针 c++ 声明
【发布时间】:2011-09-14 14:36:14
【问题描述】:
template <typename T>
class Node
{...};

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

将无法编译我必须将指针声明为

Node<int>* ptr;

为什么我还没有创建类的时候声明指针的时候要指定类型,为什么编译器要知道它会指向什么类型。是否不可能创建一个通用指针并在之后决定我要为其分配什么类型。

【问题讨论】:

  • 到目前为止它还没有出现在任何答案中,我认为它不值得写一个,但这里有一个重要的一点:Node 不是一种类型。它是一个模板。确实是 class 模板,但只有 Node&lt;int&gt;Node&lt;double&gt;Node&lt;Node&lt;void&gt; &gt; 这样的东西是类型; Node 将永远是一个模板,并且只有指向类型的指针。没有指向模板的指针。
  • 这是非常重要的一点,它确实应该出现在答案中,而不仅仅是在评论中。
  • 正确的语法不应该是 Node&lt;int&gt;* ptr = new Node&lt;int&gt;(); 吗?我认为() 应该在场。
  • @motiveicgeek 这是可选的

标签: c++ class templates pointers declaration


【解决方案1】:

模板在编译时解析类型。当您将新的Node&lt;int&gt; 对象分配给它时,指针必须在编译时知道它到底是什么类型。

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

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

class NodeBase
{ ... }

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

NodeBase* ptr;

【讨论】:

  • @Mike,您设法重写了我的完整答案。你确定那是你的意图吗?
  • 我所做的只是在Node&lt;int&gt;Node&lt;std::vector&gt; 周围添加反引号,以将它们格式化为代码而不是文本。没有这种格式,这句话读作“Node and Node can be very different”,这是没有意义的。
  • @Yola,我不太清楚你的意思是什么?问题不在于虚函数调用的开销。虚函数在某些情况下没有其他选择,即在运行时函数解析时。
【解决方案2】:

简单的答案是因为 C++ 使用(相当)严格的静态类型 检查。 Node&lt;int&gt; 是与 Node&lt;double&gt; 完全无关的类型, 当编译器看到ptr-&gt;doSomething()时,它必须知道是否 拨打Node&lt;int&gt;::doSomething()Node&lt;double&gt;::doSomething()

如果您确实需要某种动态通用性,那么 实际类型 ptr 将指向只会在运行时知道,你需要 定义一个基类,并从中派生。 (这是一个相当普遍的 类模板从非模板基派生的习惯用法,准确地说 以便在运行时解决指针的一般性。)

【讨论】:

    【解决方案3】:

    为什么我还没有创建类的时候声明指针的时候要指定类型,为什么编译器要知道它会指向什么类型。

    你可以用指针做很多事情,这里只列举几个:

    • 根据指针的类型调用多个函数之一
    • 从中索引(假设它指向此类对象的连续数组中的第一个元素)
    • 获取指向对象的大小
    • 将其传递给指针类型为参数的模板

    为了让编译器生成代码来有效地执行这些操作,它需要知道指针的类型。如果它推迟决定直到它看到指针的类型,那么它需要:

    • 为指针以后可能采用的每种可能类型编译高效代码(制作一个非常臃肿的程序),或者
    • 创建可以通过一些最坏情况的悲观笨拙行为来处理所有可能类型的低效代码,或者
    • 将自身的副本(编译器)嵌入到您的 C++ 程序中,这样它就可以在获得必要信息时完成工作 - 这会使每个琐碎的程序变得庞大(而且速度很慢)

    难道不能创建一个通用指针,然后再决定我要为其分配什么类型。

    有点……你有很多选择:

    • 使用void*,但在它可以再次对指向的类型进行有意义的操作之前,您需要手动将其转换回该类型:在您的情况下,这意味着在某处记录它当时的内容,然后有单独的代码对于每一种可能性
    • 使用boost::any&lt;&gt; - 很像void*,但内置了安全性
    • 使用boost::variant&lt;&gt; - 更安全、更方便,但您必须在创建指针时列出可能的指向类型
    • 使用运行时多态对象系列和虚拟调度...这是经典的面向对象编程...您有一个指向“抽象”Node 的指针,它声明了您将使用的共享函数和成员数据对任何特定类型的节点进行操作,然后模板化 Node 类派生自该抽象 Node 并实现特定于类型的函数版本。然后使用virtual 函数通过指向基类的指针调用它们。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-05-02
          • 1970-01-01
          • 2018-05-26
          • 1970-01-01
          • 2018-05-20
          • 2012-04-04
          • 1970-01-01
          相关资源
          最近更新 更多