下面是一个典型ATL风格的类定义:
#include "stdafx.h"
#include "iostream.h"
template <class T>
class B1
{
public:
void SayHi()
{
T* pT = static_cast<T*>(this);
pT->PrintClassName();
}
protected:
void PrintClassName()
{
cout<<"This is B1";
}
};
class D1 : public B1<D1>
{
// No overridden functions at all
};
class D2 : public B1<D2>
{
protected:
void PrintClassName()
{
cout<<"This is D2";
}
};
int main(int argc, char* argv[])
{
D1 d1;
D2 d2;
d1.SayHi(); // prints "This is B1"
d2.SayHi(); // prints "This is D2"
return 0;
}
这段代码很有蛊惑性,看似完全正确,但是编译它,你将得到错误提示: error C2248: 'D2::PrintClassName' : cannot access protected member declared in class 'D2' ,也即在访问D2::PrintClassName方法时,没有足够的权限。
修正方法很简单,只需将D2::PrintClassName的方法改用public修饰即可。
若要分析原因,也是很容易的,而且还非常有趣。调用d1.SayHi并没有问题,原因在于d1.SayHi方法调用的PrintClassName方法并未被派生类D1重写,仍然还是B1中的PrintClassName方法,它和SayHi方法拥有相同类型的this指针。换句话说,它们定义在同一个类体中,类方法调用同类方法总是成功的。甚至将B1::PrintClassName方法修饰为private,仍然是正确的。
同理,调用d2.SayHi将出现问题,原因在于d2.SayHi方法调用的PrintClassName方法已经被派生类D2重写,二者的this指针类型完全不同了。换句话说,它们并不定义在相同的类体中,所以需要进行权限检查。