zoukankan      html  css  js  c++  java
  • Effective C++ 笔记 —— Item 33: Avoid hiding inherited names.

    C++'s name-hiding rules do just that: hide names. Whether the names correspond to the same or different types is immaterial. 

    int x; // global variable
    void someFunc()
    {
        double x; // local variable
        std::cin >> x; // read a new value for local x
    }

    We know that when we’re inside a derived class member function and we refer to something in a base class (e.g., a member function, a typedef, or a data member), compilers can find what we’re referring to because derived classes inherit the things declared in base classes. The way that actually works is that the scope of a derived class is nested inside its base class's scope. For example:

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

    The only thing that matters in this discussion is that they’re names. What they're names of is irrelevant.

    Consider the previous example again, except this time let’s overload mf1 and mf3, and let's add a version of mf3 to Derived. (As Item 36 explains, Derived's declaration of mf3 — an inherited non-virtual 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: public Base 
    {
    public:
        virtual void mf1();
        void mf3();
        void mf4();
        // ...
    };

    The scope-based name hiding rule hasn't changed, so all functions named mf1 and mf3 in the base class are hidden by the functions named mf1 and mf3 in the derived class. From the perspective of name lookup, Base::mf1 and Base::mf3 are no longer inherited by Derived!

    Derived d;
    int x;
    // ...
    d.mf1(); // fine, calls Derived::mf1
    d.mf1(x); // error! Derived::mf1 hides Base::mf1
    
    d.mf2(); // fine, calls Base::mf2
    d.mf3(); // fine, calls Derived::mf3
    d.mf3(x); // error! Derived::mf3 hides Base::mf3

    As you can see, this applies even though the functions in the base and derived classes take different parameter types, and it also applies regardless of whether the functions are virtual or non-virtual. 

    Unfortunately, you typically want to inherit the overloads.You do it with using declarations:

    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; // make all things in Base named mf1 and mf3
        using Base::mf3; // visible (and public) in Derived’s scope
        virtual void mf1();
        void mf3();
        void mf4();
        // ...
    };

    Now inheritance will work as expected:

    Derived d;
    int x;
    // ...
    d.mf1(); // still fine, still calls Derived::mf1
    d.mf1(x); // now okay, calls Base::mf1
    d.mf2(); // still fine, still calls Base::mf2
    d.mf3(); // fine, calls Derived::mf3
    d.mf3(x); // now okay, calls Base::mf3 (The int x is implicitly converted to a double so that the call to Base::mf3 is valid.)

    This means that if you inherit from a base class with overloaded functions and you want to redefine or override only some of them, you need to include a using declaration for each name you’d otherwise be hiding. If you don't, some of the names you’d like to inherit will be hidden.

    It's conceivable that you sometimes won't want to inherit all the functions from your base classes.For example, suppose Derived privately inherits from Base, and the only version of mf1 that Derived wants to inherit is the one taking no parameters. A using declaration won't do the trick here, because a using declaration makes all inherited functions with a given name visible in the derived class. No, this is a case for a different technique, namely, a simple forwarding function:

    class Base 
    {
    public:
        virtual void mf1() = 0;
        virtual void mf1(int);
        // ... // as before
    };
    
    class Derived: private Base {
    public:
        virtual void mf1() // forwarding function; implicitly inline — see Item 30. (For info on calling a pure virtual function, see Item 34.)
        { 
            Base::mf1();
        } 
    }; 
    
    // ...
    
    Derived d;
    int x;
    d.mf1(); // fine, calls Derived::mf1
    d.mf1(x); // error! Base::mf1() is hidden

    Things to Remember:

    • Names in derived classes hide names in base classes. Under public inheritance, this is never desirable.
    • To make hidden names visible again, employ using declarations or forwarding functions.
  • 相关阅读:
    PHP数字签名算法
    PHP日期相关类
    浏览器常见bug及解决办法
    PHPer整理的前端开发知识
    小程序之轮播图(2020.4.13更新)
    Android APK反编译 apktool使用教程
    秒懂-单列布局水平居中布局
    一句话搞定-phpStudy安装yaf扩展
    Git的简单安装
    人人都能读懂的css3 3d小demo
  • 原文地址:https://www.cnblogs.com/zoneofmine/p/15266459.html
Copyright © 2011-2022 走看看