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

1、C++的名称遮掩规则

名称遮掩规则做的事就是:遮掩名称。

  • 假如这个名称是一个变量,那么无论这两个变量的类型是否相同,都会被遮掩。
  • 假如这个名称是一个函数,那么无论函数的参数有几个,无论这个同名的函数有几个重载的版本,这些函数全都会被遮掩。

2、派生类的成员函数内查找名称的顺序

  • 先在成员函数体内查找(local作用域)。
  • 找不到的情况下,在派生类内查找。
  • 找不到的情况下,在派生类所继承的基类内查找。
  • 找不到的情况下,在派生类所属namespace查找。
  • 找不到的情况下,在global作用域查找。
  • 找不到的情况下,则会报错。

3、名称遮掩与继承

情况一:
在这里插入图片描述
派生类mf1() 覆盖基类mf1(),此时基类中并没有重载的mf1()函数。在这样的情况下,一切运作正常。
情况二:
在这里插入图片描述
基类中,mf1()和mf3()有重载的版本,此时在派生类中修改mf1()、mf3()时,修改的那本版本的函数正常运作,没被修改的版本的成员函数被遮盖。此时,实际上就违背了public继承的is-a关系。因此应该避免这种情况。

4、如何解决上述名称遮掩问题?

方案一:

  • 给需可能被遮掩的名称:加using 基类名称声明。放在派生类定义的public作用域中。

方案二:

如果编译器不支持using声明,public继承的名称遮掩问题也可以用转交函数实现。
即:为每一个基类版本写转交函数。

5、private继承和public继承与名称遮掩

  • public继承派生类不能只继承一部分成员,必须要全部继承。即:塑模is-a关系。
  • private继承可以继承一部分成员。此时使用转交函数技术实现这一需求。

使用转交函数实现部分继承:

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()被遮掩了

在这里转交函数做到了两点:

  • 转交函数内部调用基类的mf1()无参函数,因此实现了继承基类的无参mf1()
  • 而同时由于mf1遮掩了基类的mf1(),因此其他版本的mf1()在该private继承的派生类中是不可见的。

这便实现了只继承基类的一部分。

posted @ 2019-12-19 10:12  江南又一春  阅读(121)  评论(0编辑  收藏  举报