C++类中的虚函数不能为模板函数
首先,理解模板的原理。例如,定义了一个模板函数:
template<typename A>
void Func(const A& a) {
std::cout <<"Func(const A& a) : "<< a << std::endl;
}
编译器在编译期间,会检查代码中哪些地方使用了这个函数,例如,如果在整个程序中使用到了两种类型:Func<int>(9);
Func<float>(9.3); 则编译器会生成两份函数的二进制代码:void Func(const int& a),以及void Func(const float& a)。
由于对于类的虚函数来说,其是否被调用是在程序运行的时候才知道,因此编译阶段不知道需要生成几份函数。 例如,基类是Base,有两个子类A和B, 代码中使用基类的指针来调用子类的虚函数 ,在编译阶段并不能知道调用的是哪个子类的虚函数,因此,编译器不知道类A和B中的模板函数被调用的情况,因此,不知道需要生成几份函数。
每个含有虚函数的类中都有一个虚函数表,该虚函数表存储着该类的所有的虚函数的地址,因此,虚函数为模板函数时,该表的大小是不知道的,因此编译器禁止! 虚函数为模板函数的情况下,编译阶段不能确定类的虚函数表的大小原因:下文有提到"However, the number of instantiations of a member function template is not fixed until the entire program has been translated". 例如,一般一个类定义在一个单独的文件中,编译器编译这个文件时并不知道其他文件对该类的virtual func的调用情况,所以无法确定模板虚函数的实例化个数!
但是,类的普通的成员函数是可以为模板函数的。例如A.h中定义了void A::f(T)这个模板函数,在main.cpp中使用该函数时需要#include A.h,然后编译器在编译main.cpp时应该会生成一份对应的模板实例。
From C++ Templates The Complete Guide:
Member function templates cannot be declared virtual. This constraint is imposed because the usual implementation of the virtual function call mechanism uses a fixed-size table(虚函数表必须是fixed sized,我的盲点) with one entry per virtual function. However, the number of instantiations of a member function template is not fixed until the entire program has been translated. Hence, supporting virtual member function templates would require support for a whole new kind of mechanism in C++ compilers and linkers. In contrast, the ordinary members of class templates can be virtual because their number is fixed when a class is instantiated.
Book:
C++ Templates - The Complete Guide, 2nd Edition
Test:
#pragma once
#include <iostream>
class templateFunc
{
public:
void fun() {
}
//ok:
template<typename A>
void testFunc(const A& a) {
std::cout << "templateFunc::testFunc(const A& a) : " << a << std::endl;
}
//error: 编译器会直接报错
/*template<typename A>
virtual void testMe(const A& a) {
}*/
};
template<typename A>
void Func(const A& a) {
std::cout <<"Func(const A& a) : "<< a << std::endl;
}
int main() {
templateFunc obj;
obj.testFunc<int>(6);
Func<int>(9);
return 0;
}
可以结合模板函数与虚函数多态的机制
stack overflow上有人提到:
However, there are a few powerful and interesting techniques stemming from combining polymorphism and templates, notably so-called type erasure.
C++中的类型擦除(type erasure in c++)
C++: 类型擦除(type erasure)_Peace-CSDN博客_c++ 类型擦除
Ref:
Why class member function template can not be virtual in c++_creambean的博客-CSDN博客
c++ - Can a class member function template be virtual? - Stack Overflow