Проблема связывания, когда производный класс вызывает функцию шаблона в базовом классе - PullRequest
0 голосов
/ 29 сентября 2011

У меня есть класс База в base.h, в котором есть функция шаблона

class Base {
 template <typename T> void test(T a);
}

этот шаблон должен читаться в типе int или double, и у меня есть класс Производный , который является производным от класса Base

Я пытался вызвать функцию test в классе Derived, но у меня ошибка компоновщика.

В конце концов, я понял, что если в base.cpp я добавлю

void test(int a);
void test(double a);

не будет ошибки компилятора. Это решение кажется неудобным, есть ли лучшее решение? Спасибо

Ответы [ 3 ]

3 голосов
/ 29 сентября 2011

Шаблоны C ++ должны быть определены (при условии полного тела функции) в той же единице перевода (файл .CPP плюс все включенные файлы заголовков), где они используются. В вашем заголовочном файле все, что вы сделали, это объявили (учитывая имя и подпись) функции. В результате, когда вы включаете base.h, все, что видит компилятор, это:

class Base {
  template <typename T> void test(T a);
}

Это объявляет, но не определяет функцию. Чтобы определить его, вы должны включить тело функции:

class Base {
  template <typename T> void test(T a)
  {
    // do something cool with a here
  }
}

Причина, по которой это необходимо, заключается в том, что компилятор C ++ генерирует код для шаблонов по мере необходимости. Например, если вы звоните:

Base obj;
obj.test< int >( 1 );
obj.test< char >( 'c' );

Компилятор сгенерирует два набора машинного кода на основе шаблона Base::test, один для int и один для char. Ограничение здесь заключается в том, что определение шаблона Base::test должно быть в одной и той же единице перевода (файл .CPP), иначе компилятор не будет знать, как создать машинный код для каждой версии функции Base::test. Компилятор работает только с одним модулем перевода за раз, поэтому он не знает, определили ли вы Base::test< T > в каком-либо другом файле CPP. Он может работать только с тем, что имеет под рукой.

Это сильно отличается от того, как работают дженерики в C #, Java и аналогичных языках. Лично мне нравится думать о шаблонах как о текстовом макросе, который расширяется компилятором по мере необходимости. Это заставляет меня помнить, что полное тело функции шаблона должно быть включено в любой файл CPP, где она используется.

2 голосов
/ 29 сентября 2011

Вы должны полностью определить функцию шаблона test, прежде чем ее можно будет использовать.Самый простой способ сделать это - просто написать тело функции в заголовке в base.h:

class Base {
 template <typename T> void test(T a)
 {
    ... function body here
 }
}
0 голосов
/ 19 октября 2012

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

...