首先,我们要区分模板类虚函数和模板虚函数,话不多说,先上代码:
模板类虚函数
template<class T>
class A{
public:virtual ~A(){}virtual void foo(T &t){}
};template<class T, class R>
class B : public A<T>{R *r;
public:void foo(T &t) override{}
};//模板虚函数
class A{
public:virtual ~A(){}template<class T>virtual void foo(T &t){}
};class B : public A{
public:template<class T>void foo(T &t) override{}
};
显然模板虚函数无法通过编译,至于为什么?深究一下C++多态的实现原理,就能知道为什么不允许定义模板虚函数。
C++的多态是通过虚表实现的,对于含有虚函数的类,会为其定义一个虚表,每个实例化的对象都有一个指向该虚表的指针,所以同样的类,含有虚函数的类的实例大小比不含虚函数的多上一个指针的大小,虚表里为每个虚函数维护着一条跳转记录,这些跳转地址在编译期就被确定了,存放在类定义模块的数据段中,在程序运行期是不可修改的。
那么这跟模板虚函数有什么关系呢?
C++对于模版的处理,在编译时,编译器只对已经实例化的模板类生成对应的模板类代码,假如这些类中定义的有模板类虚函数,则对每个实例化的模板类型创建一个虚表,即第一种情况 —— 模板类虚函数,是可行的。
再看看模板虚函数为什么不行?
如上面的代码,A是一个类型,它含有模板虚函数,虽然是虚函数,但是函数符号并不确定,因为不知道模板T是一个什么类型,对于从没调用过这个模板函数的情况下,这个模板虚函数甚至都不会实例化,那么就相当于没有虚函数了。