C++继承中的名称遮掩
1)public继承中解决名称遮掩的方法——引入using声明式
所谓名称遮掩是指如果变量或函数的名称相同时,局部的会遮掩外围的,派生类会遮掩基类的,如:
1 class Base 2 { 3 private: 4 int x; 5 public: 6 virtual void mf1() = 0; 7 virtual void mf1(int); 8 virtual void mf2(); 9 void mf3(); 10 void mf3(double); 11 ... 12 }; 13 14 class Derived : public Base 15 { 16 public: 17 virtual void mf1(); 18 void mf3(); 19 void mf4(); 20 ... 21 };
上面的代码中,base class内所有名为mf1和mf3的函数都被derived class内的mf1和mf3函数遮掩掉了,从名称查找观点来看,Base::mf1和Base::mf3不再被Derived继承!因此:
1 Derived d; 2 int x; 3 ... 4 d.mf1(); //right, 调用Derived::mf1 5 d.mf1(x); //error,因为Derived::mf1遮掩了Base::mf1 6 d.mf2(); //right, 调用Base::mf2 7 d.mf3(); //right, 调用Derived::mf3 8 d.mf3(x); //error, 因为Derived::mf3遮掩了Base::mf3
为了解决上面的问题,可以引入using声明式:
1 class Derived:public Base 2 { 3 public: 4 using Base::mf1; 5 using Base::mf3; 6 virtual void mf1(); 7 void mf3(); 8 void mf4(); 9 ... 10 };
在上面的代码引入using之后,Base中任何名称为mf1和mf3的成员在Derived类中都可访问了,实现了真正的public继承。
2)在private继承中解决名称遮掩的方法
在上面的例子中Base class对mf1和mf3进行了重载,在Derived class中如果使用using声明式,那么Base class中所有名称为mf1和mf3的成员在Derived class中都变为可见,这对public继承是合理的,因为public继承意味着"is a"的关系,但是对于private继承,没有这方面的要求,如果此时用户只想对Base class重载函数中的某个可见,而不要求对所有名称相同的重载函数可见,那么利用using就不可以,此时可以利用转交函数,如下:
1 class Base 2 { 3 public: 4 virtual void mf1()=0; 5 virtual void mf1(int); 6 ... 7 }; 8 9 class Derived: private Base 10 { 11 public: 12 virtual void mf1() 13 { 14 Base::mf1();// default be inlined 15 } 16 ... 17 }; 18 19 ... 20 Derived d; 21 int x; 22 d.mf1();// call Derived::mf1 23 d.mf1(x);//error! Base::mf1() is hidden
对以上做出总结:派生类的名称会遮掩基类的名称,解决方法有引入using声明式和使用inline转交函数两种,前者使得基类与对应名称相同的所有成员都为派生类可见,这在public继承中是很合理的,后者则可以具体到重载函数中的某一个才可被派生类可见。
以上整理自Effective C++中文版第三版case 33.