// #include "stdafx.h" // 先定义一个接口 template < class DataType > class A { public: virtual int SomeFunc(const DataType &Value ) = 0; }; // B来实现这个接口为这样,竟然编译不过! template< class something1, class something2 > class B : public A< char* > { public: virtual int SomeFunc( const char* &Value ) { return 0; }; }; // 改成这样编译才能通过 template< class something1, class something2 > class C : public A < char* > { public: virtual int SomeFunc( char* const &Value ) { return 0; }; }; // const char* 和 char* const 的含义是大不一样的,可是经过模板的参数化过程 // 后,混淆了两者,这应该算个BUG了吧? int _tmain(int argc, _TCHAR* argv[]) { B< int, int > b; // 注释此行后编译通过 C< int, int > c; return 0; } 其中那段注释很有意思,但是这个不是bug,相反,应该说这样才是符合C++规范的, 不是编译器混淆了两者,而是我们的作者混淆了两者。 再来看const char* &p 和 char* const &p 两种引用: 两者都是对一个对象的引用。 但是前者的“这个对象”是 const char*,一个指向 const char 的指针,注意!虽 然这个指针指向的char不可以改变,但这个指针本身的值是可以改变的,也就是说, 他可以被改变而指向另一个 const char 对象。 后者的“这个对象”则是char*, 一个指向char的指针。这个指针指向的东西是可以 改变的,但是这个指针本身是不能改变的,你不能让他指向另一个char对象。 如果你觉着这段表述不够清晰,请自行编译一下下面这段代码: void fconst( const char* & p ) { *p = 'L'; // error C2166: l 值指定常数对象 p ++; // OK! } void constf( char* const & p ) { *p = 'L'; // OK! p ++ ; // error C2166: l 值指定常数对象 } int main () { char str[] = "Hello world"; char* p = &str[2]; fconst(p); constf(p); } 现在const char *& 与 char* const& 的区别已经清楚了,那么我们看模板如何特化的 作者的SomeFunc的参数是一个DataType的const reference,所谓的const reference, 是说你不能再改变这个reference所引用的对象的状态,因此 const DataType & 和 DataType const &是等价的,也就是说, template A<DataType> 的函数SomeFunc 的参数是一个对某个对象的常引用,这个引用所引用的对象的状态在函数作用域内不 可以被改变。 那么很明确吧,A< char* > 被特化作为 class B 和 C 的基类,那么它的纯虚成员函数 SomeFunc的参数就被特化为对于char* 的const reference了,SomeFunc也就具有形式 int SomeFunc( char* const& ),因此如果定义成int SomeFunc(const char* &Value) 不会与纯虚函数匹配,自然变成的普通的虚函数,而纯虚函数没有定义: error C2259: “B<something1,something2>” : 不能实例化抽象类 with [ something1=int, something2=int ] 由于下列成员: “int A<DataType>::SomeFunc(const DataType & )” : 未定义纯虚函数 with [ DataType=char * ] tempBUG.cpp(5) : 参见“A<DataType>::SomeFunc”的声明 with [ DataType=char * ]