// TemplateBug.cpp : 定义控制台应用程序的
入口点。
//
#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
的函数SomeFunc
的参数是一个对某个对象的常引用,这个引用所引用的对象的状态在函数作用域内不
可以被改变。
那么很明确吧,A< char* > 被特化作为 class B 和 C 的基类,那么它的纯虚成员函数
SomeFunc的参数就被特化为对于char* 的const reference了,SomeFunc也就具有形式
int SomeFunc( char* const& ),因此如果定义成int SomeFunc(const char* &Value)
不会与纯虚函数匹配,自然变成的普通的虚函数,而纯虚函数没有定义:
error C2259: “B” : 不能实例化抽象类
with
[
something1=int,
something2=int
]
由于下列成员:
“int A::SomeFunc(const DataType & )” : 未定义纯虚函数
with
[
DataType=char *
]
tempBUG.cpp(5) : 参见“A::SomeFunc”的声明
with
[
DataType=char *
]