Указатель на класс шаблона c ++ декларация - PullRequest
16 голосов
/ 14 июня 2011
template <typename T>
class Node
{...};

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

Не удастся скомпилировать. Мне нужно объявить указатель как

Node<int>* ptr;

. Почему я должен указывать тип при объявлении указателя? Я еще не создал класс, почемукомпилятор должен знать, на какой тип он будет указывать.И невозможно ли создать общий указатель и впоследствии решить, какой тип я хочу назначить.

Ответы [ 5 ]

28 голосов
/ 14 июня 2011

Шаблоны разрешают типы во время компиляции. Когда вы назначаете ему новый объект Node<int>, указатель должен знать во время компиляции, какой именно это тип.

Node<int> и Node<std::vector> могут сильно различаться в двоичных файлах (двоичная компоновка вашего объекта полностью изменяется в соответствии с параметром шаблона), поэтому нет смысла иметь неразрешенный тип указателя на шаблон.

Сначала вы должны определить общий родительский класс для ваших узлов:

class NodeBase
{ ... }

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

NodeBase* ptr;
9 голосов
/ 14 июня 2011

Простой ответ заключается в том, что C ++ использует (довольно) строгую статическую проверку типов.Node<int> - это совершенно не связанный тип с Node<double>, и когда компилятор видит ptr->doSomething(), он должен знать, вызывать ли Node<int>::doSomething() или Node<double>::doSomething().

Если вам нужен какой-тодинамическая универсальность, на которую будет указывать фактический тип ptr, будет известна только во время выполнения, вам нужно определить базовый класс и получить его.(Это довольно распространенная идиома для шаблона класса, получаемого из не шаблонной базы, именно для того, чтобы универсальность указателей могла быть решена во время выполнения.)

4 голосов
/ 14 июня 2011

Почему я должен указывать тип при объявлении указателя Я еще не создал класс, почему компилятор должен знать, на какой тип он будет указывать.

Есть много вещей, которые вы можете делать с указателем, просто перечислите очень мало:

  • вызов одной из многих функций на основе указателя типа указателя
  • изон (при условии, что он указывает на первые элементы в непрерывном массиве таких объектов)
  • принимает размер объекта, на который указывает указатель
  • передает его в шаблон, где указатель -type является параметром

Чтобы компилятор генерировал код для эффективного выполнения этих задач, ему необходимо знать тип указателя.Если он отклоняет решения до тех пор, пока не увидит тип указателя, то ему нужно будет либо:

  • скомпилировать эффективный код для каждого возможного типа, который может принять указатель позднее (создание чрезвычайно раздутой программы),или
  • создайте неэффективный код, который может обрабатывать все возможные типы с помощью некоторого пессимистического неуклюжего поведения в худшем случае, или
  • вставьте свою копию (компилятор) в вашу программу C ++, чтобы она могла завершитьэто работа, когда она получает необходимую информацию - это делает каждую тривиальную программу огромной (и медленной)

И невозможно ли создать общий указатель и впоследствии решить, какой тип я хочуназначьте его.

Вид ... у вас есть много вариантов:

  • используйте void*, но прежде чем он сможет осмысленно работать с указанным типомопять же, вам нужно вручную привести его обратно к этому типу: в вашем случае это означает запись куда-то того, что было тогда, с отдельным кодом для каждой возможности
  • use boost::any<> - очень похоже на void*, но со встроенной системой безопасности
  • use boost::variant<> - намного безопаснее и удобнее, но вы должны перечислить возможныетипы при создании указателя
  • используют полиморфное семейство объектов времени выполнения и виртуальную диспетчеризацию ... это классическое объектно-ориентированное программирование ... у вас есть указатель на "абстрактный" Node, который объявляет общийфункции и данные-члены, которые вы будете использовать для работы с любым конкретным типом узла, тогда шаблонный класс Node является производным от этого абстрактного Node и реализует специфичные для типа версии функций.Затем они вызываются через указатель на базовый класс с использованием virtual функций.
1 голос
/ 14 июня 2011

Как отмечали Нил Баттерворт и Люк Дантон, у вас не может быть указателя типа Node *, потому что Node не является типом. Это шаблон. Да, Node - это шаблон класса, но этот class здесь просто определяет тип шаблона. Один из способов взглянуть на это: так же, как классы и экземпляры классов - это очень разные вещи, так и шаблоны и экземпляры шаблонов. Именно такие экземпляры шаблонов, такие как Node, являются классами. Шаблон класса - это какой-то другой зверь.

1 голос
/ 14 июня 2011

Всякий раз, когда вы создаете какой-либо объект (включая указатели) в C ++, должен быть известен полный тип объекта.В вашем коде нет такого типа, как Node, поэтому вы не можете создавать экземпляры указателей на него.Вам нужно переосмыслить, как вы разрабатываете и пишете свой код.

...