1.不能为虚函数的原因:
编译器在编译一个类的时候,需要确定这个类的虚函数表的大小。一般来说,如果一个类有N个虚函数,它的虚函数表的大小就是N,如果按字节算的话那么就是4*N。
如果允许一个成员模板函数为虚函数的话,因为我们可以为该成员模板函数实例化出很多不同的版本,也就是可以实例化出很多不同版本的虚函数,那么编译器为了确定类的虚函数表的大小,就必须要知道我们一共为该成员模板函数实例化了多少个不同版本的虚函数。显然编译器需要查找所有的代码文件,才能够知道到底有几个虚函数,这对于多文件的项目来说,代价是非常高的,所以才规定成员模板函数不能够为虚函数。
举个例子:
class Calc
{
public:
template virtual T Add(const T& lhs,const T& rhs)
{
T sum = lhs + rhs;
return sum;
}
};
void main()
{
Calc ins;
int nResult = ins.Add(1,2);
double fResult = ins.Add(1.0,2.0);
}
那么编译器需要查看main的代码,才能够知道类Calc一共有两个虚函数,一个是
virtual int Add(const int&,const int&),另一个是
virtual double Add(const double&,const double&)。
因为只有这样才能够确定该类的虚函数表的大小为2,虽然可行,但是费事,代价高。
2.不能够有默认参数的原因:
这里所说的默认参数有两种,必须分清楚,第一种是函数的默认参数,第二种是函数模板
的默认模板参数。
成员模板函数和普通函数一样,可以有函数的默认参数(第一种),
但是不可以有函数模板的默认模板参数(第二种)。如:
第一种的情况:
template
T sum(T* b,T* e,T result = T()) //这里的result就是函数的默认参数,允许
{
while(b!=e)
result += *b++;
return result;
};
第二种的情况:
template //这里的char为默认模板参数,不允许
T f(T a, T b)
{
return a + b;
};
之所以不允许有函数模板的默认模板参数,是因为函数模板的模板参数是在调用
的时候编译器根据实参的类型来确定的,如对于上面的第二种情况,
int result = f(1,2) //int f(int a,int b),确定T为int
double result = f(1.0,2.0) //double f(double a,duoble b)),确定T为double
那么template中的T的缺省值char就毫无意义了,也毫无必要。