朱金灿
最近看《ATL开发指南》(英文名《ATL Develper’s Guide》 [美]Tom Armstrong Ron Patton著 董梁 丁杰 李长业 等译 董梁 审校),在该书的1.6 节中碰到一个值得商榷的地方。
1.6 ATL如何使用模板
首先我们分析一下下面两个类:
class CBase
{
public:
CBase(){}
~CBase() {}
void BaseMethod()
{
cout<<"BaseMethod in Base"<<endl;
}
};
class CMath:public CBase
{
public:
CMath() {}
~CMath() {}
void BaseMethod()
{
cout<<"BaseMethod in Cmath"<<endl;
}
};
template<class T>
class CComObject :public T
{
public:
CComObject(){}
~CComObject(){}
void CallBaseMethod()
{
T* pT = static_cast<T*>(this);
pT->BaseMethod();
}
};
int main(int argc, char* argv[])
{
CComObject<CMath> *pMath = new CComObject<CMath>;
pMath->CallBaseMethod();
delete pMath;
return 0;
}
作者列出了上面这个例程,然后说:CComObject类是根据模板生成的,因此它需要一个类参数。因此,你可以看到,该参数在CComObject里被用来基类的替换量。这意味着CComObject最终会通过模板参数所指定的类派生出来。CComObject是一个通用的类,它调用了基类里的特定方法。在CComObject里另外一个有趣的方面是调用基类方法的方式。通过把基类作为一个模板参数进行传递并使用该类型对类实现指针进行类型转换,就可以得到指向基类实现的一个直接指针。
在这里,重要的一点是我们并没有虚函数来覆盖上级类的特性。ATL开发队伍里的程序设计人员竭力使ATL更加高效、更加有效。在大的类层次里,调用虚函数的代价将非常高昂(主要是速度和代码长度方面),而ATL无须使用虚函数也可以完成相同的功能。
在这里我发现作者的文字描述和代码是互相矛盾的。一方面作者宣称在CComObject里另外一个有趣的方面是调用基类方法的方式。通过把基类作为一个模板参数进行传递并使用该类型对类实现指针进行类型转换,就可以得到指向基类实现的一个直接指针。照他的说法,在main函数里调用代码应该是这样的:
CComObject<CBase> *pMath = new CComObject<CMath>;
而不是CComObject<CMath> *pMath = new CComObject<CMath>;
而CComObject<CBase> *pMath = new CComObject<CMath>;
这样是编译不通过的,出现错误:
error C2440: 'initializing' : cannot convert from 'class CComObject<class CMath> *' to 'class CComObject<class CBase> *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
(编译环境:英文版 XP sp2, Visual C++ 6.0 sp6)
如果是CComObject<CMath> *pMath = new CComObject<CMath>;,它不过是调用CMath的成员函数BaseMethod,只不过这个成员函数有点特殊,和基类的一个成员函数名字相同罢了。
void CComObject::CallBaseMethod()
{
T* pT = static_cast <T*> (this);
pT-> BaseMethod();
}
我的理解是这里不过是一个指针转换,将派生类指针转换为基类指针,然后调用基类函数。这跟虚函数有什么关系呢?要知道虚函数的一个重要作用是基类指针指向派生类对象,能够调用派生类定义的函数。因此我觉得作者拿这一点跟虚函数比较是十分扯淡的。
{
T* pT = static_cast <T*> (this);
pT-> BaseMethod();
}
我的理解是这里不过是一个指针转换,将派生类指针转换为基类指针,然后调用基类函数。这跟虚函数有什么关系呢?要知道虚函数的一个重要作用是基类指针指向派生类对象,能够调用派生类定义的函数。因此我觉得作者拿这一点跟虚函数比较是十分扯淡的。
此外我希望看过此书的朋友能够和我讨论一下这个问题。(此书在网上可以下载到pdf电子版,如CSDN的下载频道)。