[原创文章欢迎转载,但请保留作者信息]
Justin 于 2010-03-24
首先看一个例子:
templatetypename T>
class TBase
{
public:
void HeyIhaveOneMillionDollar();
void HeyIOwnABenz();
//..
};
templatetypename T>
class Derived : public TBaseT>
{
public:
void DaddySays()
{
//..
HeyIOwnABenz();
//..
}
//..
};
这样的代码是通不过编译的,问题在DaddySays()中调用的HayIOwnABenz():
咋一看貌似很正常,Derived继承了父类TBase,就应该可以用老爸的资产;可是问题在于这个老爸不简单:TBase是模板类。对于模板类来说,有一种东西叫做模板的特化。(
这里和
这里都有提到过)
一言盖之,个人认为可以理解为模板的重载。比如说下面的一个“彻底的重载”,TBase的全特化:
template<>
class TBasechar>
{
public:
void WellIHaveOnlyOnePenny();
};
专为char类型全特化的TBase没有了HeyIHaveOneMillionDollar()也没有HeyIOwnABenz(), 只有一个WellIHaveOnlyOnePenny()。在这种情况下,Derived类中DaddySays()的实现就显然有问题了:这个“重载”老爸的资产不是原来的那么富有了!
于是,为了避免以上情况的发生,编译器采取了保守的做法:不能通过编译。
完了,老爸都不可靠,俺还能靠谁……靠大师!大师在这个时候出现了,还指出了三条出路:
1. 用->。
templatetypename T>
class Derived : public TBaseT>
{
public:
void DaddySays()
{
//..
this->HeyIOwnABenz();
//..
}
//..
};
2. 用using。
templatetypename T>
class Derived : public TBaseT>
{
public:
using TBaseT>::HeyIOwnABenz;
void DaddySays()
{
//..
HeyIOwnABenz();
//..
}
//..
};
3.显式声明。大师补充说明这种方法最好不用,因为如果被调用的是虚函数,那么如此显式的声明会使得虚拟机制的动态绑定失效。
templatetypename T>
class Derived : public TBaseT>
{
public:
void DaddySays()
{
//..
TBaseT>::HeyIOwnABenz();
//..
}
//..
};
问题得以解决,不过有点莫名其妙。个人认为是用来唬编译器用的:“我的“老爸”真的有这个接口!!”
只有当父类真的有提供相应的接口,才不会有问题,否则还是过得了初一过不了十五@#¥%
因为,如果真的有下面的程序,最后还是无法编译通过。
TBasechar> PoorDaddy;
PoorDaddy.DaddySays(); // won't compile, as PoorDaddy don't have the interface named HeyIOwnABenz()