Effective C++ 条款43 学习处理模板化基类内的名称
1. 在继承模板基类时,C++拒绝在模板化基类(templatized base classes)内寻找继承而来的名称,例如,对于以下模板基类:
template<typename T> class Base{ public: void fun(){ ... } ... private: ... }
以下代码通不过编译:
template<typename T> class Derived:public Base<T>{ public: void useFun(){ fun(); //通不过编译,因为编译器拒绝在Base类模板中查找fun } ... private: ... }
因为基类模板(base classe templates)有可能被特化,而那个特化版本可能不提供和一般性template相同的接口,因而C++拒绝在模板化基类中查找继承而来的名称.
2. 解决方法有三:
1). 在base class函数调用动作之前加上this->,即将对fun的调用改为如下:
this->fun();
2). 使用using 声明式,使编译器在模板作用域中查找改名字,即在Derived中加入:
using Base<T>::fun;
这里using声明式的作用和条款33不同,它解决的并不是基类名字被派生类掩盖的问题,而是编译器不进入base class作用域内查找的问题
3). 明确指出被调用的函数位于base class内,即将对fun的调用改为如下:
Base<T>::fun();
这种方式的缺点在于,如果被调用的函数是虚函数,上述的"明确资格修饰"(explict qualification)会关闭"virtual绑定行为".
3. 从名称可视点的角度出发,2中的每一个解法所做事情都相同:对编译器承诺"base classes template的任何特化版本都将支持其一般化版本所提供的接口".这个承诺是编译器在解析像Derived这样的派生类模板(derived class template)所需要的.但如果这个承诺未被实现即特化的Base不支持派生类模板Derived所要求的接口,最终还是不能通过编译.C++的策略是较早诊断,因此它假设它对那些base classes的内容毫无所悉的缘故.