我们都知道,内层作用域会掩盖外层作用域的名称。至于名称类型是否相同并不重要,如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声明式或转交函数。