[effectiv c++]条款33:避免遮掩继承而来的名称(重载,覆盖,隐藏)

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();
    ……
}

void Derived::mf4()
{
    ……
    mf2();
    ……
}

当编译器看到mf4中的mf2,必须估算它指涉(refer to)什么东西。编译器的做法是查找各作用域,看看有没有mf2的声明式。
下面是查找顺序:
1. 查找local作用域(也就是mf4覆盖的作用域)。
2. 查找mf4函数外围作用域,也就是 class Derived 覆盖的作用域。
3. 再往外围移动,查找 class Base 的作用域(本例在 class Base 中找到 mf2)。
4. 查找含有 Base 的 namespace 的作用域。
5. 查找global作用域

因此,这种查找方式会造成“名称遮掩现象”。

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();
    ……
}

void Test()
{
    Derived d;
    int x;
    ……

    d.mf1();    // correct  调用Derived::mf1
    d.mf1(x);   // error    Derived::mf1 遮掩了 Base::mf1
    d.mf2();    // correct  调用Base::mf2
    d.mf3();    // correct  调用Derved::mf3
    d.mf3(x);   // error    Derived::mf3 遮掩了 Base::mf3
}

如上述代码,即使Base和Derived内的函数有不同的参数类型,“名称遮掩”也适用,且无论式virtual或non-virtual一体适用。

然而,is-a关系是public继承的基石,我们几乎总是要推翻这个“名称遮掩行为”

方法一:使用using
为Base中那些原本会被遮掩的每个名称引入一个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;    //让Base class内命名为mf1和mf3的所有东西
    using Base::mf3;    //在Derived作用域内都可见(并且public)
    virtual void mf1();
    void mf3();
    void mf4();
    ……
}

void Test()
{
    Derived d;
    int x;
    ……

    d.mf1();    // correct  调用Derived::mf1
    d.mf1(x);   // correct  调用Base::mf1
    d.mf2();    // correct  调用Base::mf2
    d.mf3();    // correct  调用Derved::mf3
    d.mf3(x);   // correct  Base::mf3
}

方法二:使用转交函数

假设Derived以private继承Base,而Derived唯一想继承mf1的无参数版本,那么不能使用using,因为用using会使所有同名函数在Derived class中都可见。因此我们采用一个简单的转交函数。

class Base
{
public:
    vitual void mf1() = 0;
    virtual void mf1(int);
    ……
};

class Derived: private Base 
{
public: 
    virtual void mf1()
    {
        Base::mf1();
    }
    ……
};

void Test()
{
    Derived d;
    int x;
    d.mf1();    // correct 调用Derived::mf1
    d.mf1(x);   // error   Base::mf1()被遮掩
}

函数重载,覆盖,隐藏

重载:

  1. 相同的范围(在同一个类中);
  2. 函数名字相同;
  3. 参数不同;
  4. virtual 关键字可有可无。

覆盖:

  1. 不同的范围(分别位于派生类与基类);
  2. 函数名字相同;
  3. 参数相同;
  4. 基类函数必须有virtual 关键字。

隐藏:

  1. 如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
  2. 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)

参考网站http://www.cnblogs.com/BeyondTechnology/archive/2010/09/20/1831441.html
http://www.cnblogs.com/txwsh1/archive/2008/06/28/1231751.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值