读书笔记:Effective C++ 炒冷饭 - Item 43 访问基类模板中的成员

读书笔记:Effective C++ 炒冷饭 - Item 43 访问基类模板中的成员
[原创文章欢迎转载,但请保留作者信息]
Justin 于 2010-03-24

首先看一个例子:
template typename T >
class  TBase
{
   
public :
      
void  HeyIhaveOneMillionDollar();
      
void  HeyIOwnABenz();
// ..
};

template
typename T >
class  Derived :  public  TBase T >
{
   
public :
      
void  DaddySays()
      {
         
// ..
         HeyIOwnABenz();
         
// ..
      }
// ..
};

这样的代码是通不过编译的,问题在DaddySays()中调用的HayIOwnABenz():
咋一看貌似很正常,Derived继承了父类TBase,就应该可以用老爸的资产;可是问题在于这个老爸不简单:TBase是模板类。对于模板类来说,有一种东西叫做模板的特化。( 这里和 这里都有提到过)
一言盖之,个人认为可以理解为模板的重载。比如说下面的一个“彻底的重载”,TBase的全特化:
template <>
class  TBase char >
{
   
public :
      
void  WellIHaveOnlyOnePenny();
};

专为char类型全特化的TBase没有了HeyIHaveOneMillionDollar()也没有HeyIOwnABenz(), 只有一个WellIHaveOnlyOnePenny()。在这种情况下,Derived类中DaddySays()的实现就显然有问题了:这个“重载”老爸的资产不是原来的那么富有了!
于是,为了避免以上情况的发生,编译器采取了保守的做法:不能通过编译。

完了,老爸都不可靠,俺还能靠谁……靠大师!大师在这个时候出现了,还指出了三条出路:
1. 用->。
template typename T >
class  Derived :  public  TBase T >
{
   
public :
      
void  DaddySays()
      {
         
// ..
          this -> HeyIOwnABenz();
         
// ..
      }
// ..
};

2. 用using。
template typename T >
class  Derived :  public  TBase T >
{
   
public :
      
using  TBase T > ::HeyIOwnABenz;
      
void  DaddySays()
      {
         
// ..
         HeyIOwnABenz();
         
// ..
      }
// ..
};

3.显式声明。大师补充说明这种方法最好不用,因为如果被调用的是虚函数,那么如此显式的声明会使得虚拟机制的动态绑定失效。
template typename T >
class  Derived :  public  TBase T >
{
   
public :
      
void  DaddySays()
      {
         
// ..
         TBase T > ::HeyIOwnABenz();
         
// ..
      }
// ..
};

问题得以解决,不过有点莫名其妙。个人认为是用来唬编译器用的:“我的“老爸”真的有这个接口!!”
只有当父类真的有提供相应的接口,才不会有问题,否则还是过得了初一过不了十五@#¥%
因为,如果真的有下面的程序,最后还是无法编译通过。
TBase char >  PoorDaddy;

PoorDaddy.DaddySays(); 
//  won't compile, as PoorDaddy don't have the interface named HeyIOwnABenz()

你可能感兴趣的:(读书笔记:Effective C++ 炒冷饭 - Item 43 访问基类模板中的成员)