zoukankan      html  css  js  c++  java
  • Effective C++:条款33:避免遮掩继承而来的名称

    (一)

    以下这段代码:

    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)。





  • 相关阅读:
    STM32F103RCT6项目RAM&ROM占用分析
    STM32使用jasson库程序卡死(freeRTOS/标准库)
    STM32使用OLED模块(SSD1306):OLED_DrawBMP()
    C语言内存管理
    C语言指针
    C语言数组
    C语言循环结构
    C语言函数
    C语言选择结构
    C语言运算符与表达式
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/6707076.html
Copyright © 2011-2022 走看看