Наследование от виртуального шаблонного класса в C ++ - PullRequest
3 голосов
/ 14 декабря 2009

Как мне наследовать от класса виртуального шаблона, в этом коде:

// test.h
class Base {
 public:
  virtual std::string Foo() = 0;
  virtual std::string Bar() = 0;
};

template <typename T>
class Derived : public Base {
 public:
  Derived(const T& data) : data_(data) { }

  virtual std::string Foo();
  virtual std::string Bar();

  T data() {
    return data_;
  }

 private:
  T data_;
};


typedef Derived<std::string> DStr;
typedef Derived<int> DInt;

// test.cpp
template<typename T>
std::string Derived<T>::Foo() { ... }
template<typename T>
std::string Derived<T>::Bar() { ... }

Когда я пытаюсь использовать DStr или DInt, компоновщик жалуется, что есть неразрешенные внешние объекты, которые Derived<std::string>::Foo() и Derived<std::string>::Bar(), и такие же для Derived<int>.

Я что-то упустил в своем коде?

EDIT: Спасибо всем. Теперь все ясно.

Ответы [ 3 ]

6 голосов
/ 14 декабря 2009

Вы должны убедиться, что функции-члены где-то созданы для всех необходимых типов.

Обычно это достигается путем определения встроенных функций шаблона в заголовочном файле, где они объявляются, так что любое использование функций приведет к их созданию.

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

6 голосов
/ 14 декабря 2009

Вам необходимо определить template<typename T> std::string Derived<T>::Foo() { ... } и template<typename T> std::string Derived<T>::Bar() { ... } в заголовочном файле. Когда компилятор компилирует test.cpp, он не знает всех возможных значений T, которые вы можете использовать в других частях программы.

Я думаю, что есть некоторые компиляторы, которые имеют связи между шагами компиляции и компоновки, которые замечают ссылки на отсутствующие экземпляры шаблона и создают их экземпляры из файла .cpp, где они объявлены. Но я не знаю, какие они есть, а функциональность найти крайне редко.

Если вы определите их в заголовочном файле, большинство компиляторов будут выдавать их как «слабый» символ в каждую единицу компиляции, на которую они ссылаются. И компоновщик выбросит все, кроме одного определения слабого символа. Это вызывает дополнительное время компиляции.

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

3 голосов
/ 14 декабря 2009

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

Даже с Comeau, вы должны использовать ключевое слово export, чтобы все работало правильно.Поскольку они единственные, кто реализует export, вполне вероятно, что вам все равно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...