編譯器在編譯一個類的時候,需要確定這個類的虛函數表的大小。一般來說,如果一個類有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 <typename T> T sum(T* b,T* e,T result = T()) //這里的result就是函數的默認參數,允許 { while(b!=e) result += *b++; return result; }; //第二種的情況: template <typename T = char>//這里的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就毫無意義了,也毫無必要。
但注意,對於上面那些可以通過函數模板的實參演繹模板參數類型的情況,指定缺省的模板實參確實沒有意義和必要。但某些情況下,有一些模板參數(比如作為函數的返回值類型)無法通過函數的實參演繹來確定,這個時候指定缺省的模板實參就很有必要,如下情況:
// 返回類型RT無法通過實參演繹獲得,這個時候指定RT的缺省實參就是非常必要的 template <typename RT, typename T1, typename T2> inline RT add(T1 a, T2 b) { return a + b; }
【轉自】http://blog.chinaunix.net/uid-20781394-id-516009.html