条款33、避免遮掩继承而来的名称

	我们都知道,内层作用域会掩盖外层作用域的名称。至于名称类型是否相同并不重要,如x的int掩盖x的double.
	现在引入继承,当派生类成员函数涉及基类的某物(成员函数,typedef,或成员变量),编译器可以找出所涉及的东西,派生继承了声明于基类的所有东西,实际运作方式是:Drived作用域嵌套于Base类作用域内。如下:
class Base
{
private:
         int x;
public:
         virtualvoid mf1()=0;
         virtualvoid mf2();
         void mf3();
         …
};
class Derived:public Base
{
public:
         virtualvoid mf1();
         void mf4();
         …
};

上述代码虽然涉及不同类型的函数及公私方式,这是为强调我们谈的是名称,和其他无关。
考虑下面派生类mf4的实现代码:
void Derived::mf4()
{
         mf2();
         ….
}
编译器查找规则:
local作用域(mf4覆盖的作用域)->Derived class覆盖作用域->Base作用域(本例已找到)->内含Base的那个namespace作用域(如果有)->全局作用域(global)
再考虑一个例子,重载mf1和mf3,然后在derived中添加一新的mf3:
class Base
{
private:
         int x;
public:
         virtualvoid mf1()=0;
         virtualvoid mf1(int);
         virtualvoid mf2();
         void mf3();
         voidmf3(double);
         …
};
class Derived:public Base
{
public:
         virtualvoid mf1();
         void mf3();
         void mf4();
         …
};

上述从名称查找规则看:基类所有名为mf1和mf3都被掩盖,故不再继承。
Derived d;
int x;
d.mf1();    //T   Derived::mf1();
d.mf1(x);  //F   Derived::mf1掩盖Base::mf1
d.mf2();             //T  Base::f2
d.mf3();     //T   Derived::mf3
d.mf3(x);   //F   Derived::mf3掩盖Base::mf3

显然,上述规则对所有不同参数类型适用,对虚函数与否也适用。
但有时候也会想继承重载函数,实际上:如果正在使用实际public继承却又不能继承重载函数,就是违反了B和D的is-a关系。我们可以使用using 声明达成目标:
class Base
{
private:
         int x;
public:
         virtual void mf1()=0;
         virtual void mf1(int);
         virtual void mf2();
         void mf3();
         void mf3(double);
         …
};
class Derived:public Base
{
public:
         using Base::mf1;  //让B类中名为mf2和mf3的函数在D内作用域内都可见(且为public)
         using Base::mf3;
         virtual void mf1();
         void mf3();
         void mf4();
         …
};

现在继承机制一如继往:
Derived d;
int x;
d.mf1();    //T   Derived::mf1();
d.mf1(x);   //T   Base::mf1
d.mf2();             //T  Base::f2
d.mf3();     //T   Derived::mf3
d.mf3(x);    //T   Base::mf3

这意味着如果想继承基类并加上重载函数,但又想重新改写其中一部分,我们可以为那些原本会遮掩的每个名称引入一个using声明式。
但有时又不想继承基类所有函数,但在public继承中绝对不可能发生,因为public继承意味着B和D这间的is-a关系。基类的public名称在public派生类内也应该是public(这也是using声明放入D内public域内原因)
但在private继承中却是有意义的,如我们想继承的那个是无参的mf1版本,此时using声明无用。因为using声明式会令继承而来的给定名的所有同名函数在D中可见,我们可以采用不同方法,即简单的转交函数,如下:
class Base
{
public:
         virtualvoid mf1()=0;
         virtualvoid mf1(int);
         …  //同前
};
class Derived:public Base
{
public:
         virtualvoid mf1() //转交函数(forwarding function)
{using Base::mf1();} //暗自成为inline  (TK30)
         …
};
….
Derived d;
int x;
d.mf1();  //T  调用Derived::mf1();    
d.mf1(x);  //F    Base::mf1被遮掩

需要记住的:
1、derived类内的名称会掩盖Base内的名称。在public继承下没人希望会这样。
2、为了让被掩盖的名称再重新可见,可以使用using声明式或转交函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值