(一)
下面这段代码:
int x; void someFunc() { double x; //local variable std::cin>>x; //read a new value to local x }
这个指涉的是local变量x,而不是global变量x,因为内存作用域会的名称遮掩外围作用域的名称。当编译器处于someFunc的作用域内并遭遇名称x时,他在local作用域内查找是否有什么东西带着这个名称。如果找到就不再找其他作用域。someFunc的x是double类型而global的x是int类型,并不要紧。C++的名称遮掩规则(name-hiding rules)所做的唯一事情就是:遮掩名称。至于名称是否是相同或不同的类型,并不重要。
(二)derived class继承声明于base class内的所有东西。derived class作用域被嵌套在base class作用域内:
class Base { private: int x; public: virtual void mf1() = 0; virtual void mf2(); void mf3(); }; class Derived : public Base { public: virtual void mf1(); void mf4(); };假设derived class内的mf4的实现像这样:
void Derived::mf4() { mf2(); }当编译器看到这里使用名称mf2,必须估算它指涉什么东西。查找各作用域,看看有没有某个名为mf2声明式。首先查找local作用域(也就是mf4覆盖的作用域),没找到任何东西名为mf2.于是查找其外围作用域,class Derived覆盖的作用域。还是没找到任何东西名为mf2.于是再往外围移动,本例为base class。在那找到一个名为mf2的东西了,于是停止查找。如果Base还是没有mf2,查找便继续下去,首先找内含Base 的那个namespace的作用域,最后往global作用域找去。
(三)
这次我们重载mf1和mf3,并添加一个新版mf3到derived去:
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: virtual void mf1(); void mf3(); void mf4(); };
base
class内所有名为mf1和mf3的函数都被derived class内的mf1和mf3函数遮掩掉了!
Derived d; int x; d.mf1(); d.mf1(x);//错误,Derived::mf1遮掩了Base::mf1 d.mf2(); d.mf3(); d.mf3(x);//错误,Derived::mf3遮掩了Base::mf3即使base class和derived classes内的函数有不同的参数类型也适用,而且不论函数是virtual或non-virtual也适用。
(四)解决上面的问题的方法!
可以用using声明式达成目标:
class Derived : public Base { public: //base class内的public名称在publicly derived class内也应该是public。 using Base::mf1; // 让base class内为mf1和mf3的所有东西 using Base::mf3; //在Derived class作用域内都可见(并且public) virtual void mf1(); void mf3(); void mf4(); }; Derived d; int x; d.mf1(); d.mf1(x);//现在没问题了,调用Base::mf1 d.mf2(); d.mf3(); d.mf3(x);//现在没问题了,调用Base::mf3这意味着如果你继承base class并加上重载函数,而你又希望重新定义或覆写(推翻)其中一部分,那么你必须为那些原本会被覆盖的每一个名称引入一个using声明式,否则某些你希望继承的名称会被覆盖。
(五)
有时候我们并不希望继承base
class的所有函数,这个时候就不能用public方式继承了,因为这违反了"base与derived classes之间的is-a关系!所以这个时候就要用private的继承方式了!
如果Derived唯一想继承的是base
class中的那个无参数版本的mf1。using在这里派不上用场,using会令继承而来的某给定名称之所有同名函数在Derived class中都可见(在这里如果用using的话,那么在base class中的所有mf1在derived class中都可见!)。所以在这种情况下,我们需要一个简单的转交函数(forwarding function):
class Base { private: int x; public: virtual void mf1() = 0; virtual void mf1(int); virtual void mf2(); void mf3(); void mf3(double); }; class Derived : private Base { public: virtual void mf1()//转交函数 { Base::mf1();//暗自转成inline } }; Derived d; int x; d.mf1();//调用的是Derived::mf1 d.mf1(x);//错误,Base::mf1()被遮掩了
请记住:
(1) derived class内的名称会遮掩base classes内的名称。在public继承下没有人希望如此。
(2) 为了让遮掩的名称再见天日,可使用using声明式或转交函数(forwarding functions)。