Вы не можете.Невозможно вызвать шаблон функции в производном классе через указатель на базу, это то, что означает «шаблоны функций не могут быть виртуальными».
Вы можете думать об этом как о том, что вызов вызываетсясоздание экземпляра шаблона функции с конкретным типом T
- если вы вызываете его с помощью int
, но динамический тип объекта, к которому вы его вызываете, неизвестен до времени выполнения (будь то A, B иличто-то еще), тогда компилятор не сможет узнать, что ему нужно создать экземпляр A::MultiplyVersion1<int>
или B::MultiplyVersion1<int>
или что-то еще.На самом деле есть нечто большее, чем это, но я думаю, что этого достаточно.
Вы можете сосредоточиться на определенных случаях, но вы не получите полного эффекта виртуальной функции.Примерно так:
struct Base {
template <typename T>
void MultiplyVersion1(const T &x, const T &y) {
A *athis = dynamic_cast<A*>(this);
if (athis) {
athis->MultiplyVersion1(x,y);
} else {
B *bthis = dynamic_cast<B*>(this);
if (bthis) {
bthis->MultiplyVersion1(x,y);
} else {
throw std::logic_error();
}
}
}
virtual ~Base() {}
};
Теперь, когда вы вызываете MultiplyVersion1<int>
через указатель на базу, создаются экземпляры A::MultiplyVersion1<int>
и B::MutiplyVersion1<int>
.Но, конечно, вы не можете легко добавить новые производные классы, что является серьезным ограничением.
Вы также можете пересмотреть вопрос о том, нужен ли вам вообще динамический полиморфизм, но это полностью зависит от того, как вы планируетеиспользовать этот базовый класс.Вы, кажется, до сих пор обходились без него.
Если все, что вам нужно от базового класса, это повторное использование кода для некоторых других функций, то вам не нужен динамический полиморфизм.Полностью исключите MultiplyVersion1
из базового класса (и, возможно, не наследуйте публично от Base
, вместо этого унаследуйте конфиденциально и добавьте функции, которые вы хотите повторно использовать с операторами using
).Если функции, которые вы хотите определить для повторного использования, вызывают MultiplyVersion1
, рассмотрите моделируемое динамическое связывание через CRTP:
#include <iostream>
template <typename Derived>
struct Base {
template <typename T>
void MultiplyVersion2(const T &x, const T &y) {
static_cast<Derived&>(*this).MultiplyVersion1(x + 1, y + 1);
}
};
struct A : private Base<A> {
friend class Base;
template <typename T> void MultiplyVersion1(T x, T y) {
std::cout << x*y << "\n";
}
using Base::MultiplyVersion2;
};
struct B : private Base<B> {
friend class Base;
template <typename T> void MultiplyVersion1(T x, T y) {
std::cout << x << " * " << y << " = " << x*y << "\n";
}
using Base::MultiplyVersion2;
};
int main() {
A a;
a.MultiplyVersion2(1,2);
B b;
b.MultiplyVersion2(1,2);
}