• EC读书笔记系列之15:条款32、33、34


    条款32 确保你的public继承塑模出is-a关系

    记住:

    ★public继承意味着is-a。适用于base class身上的每一件事情一定也适用于derived class身上,∵每一个derived class对象也都是一个base class对象。

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

    记住:

    ★derived classes内的名称会遮掩base classes内的名称。在public继承下从来无人希望如此

    ★为了让被遮掩的名称再见天日,可使用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:
            virtual void mf1();      //遮掩base的同名函数
            void mf3();            //遮掩base的同名函数
            void mf4();
            ...
    };
    
    Derived d;
    int x;
    ...
    d.mf1();   //正确,调用Derived::mf1
    d.mf1(x);  //错!因为Derived::mf1遮掩Base::mf1
    d.mf2();   //正确,调用Base::mf2
    d.mf3();   //正确,调用Derived::mf3
    d.mf3(x);  //错!因为Derived::mf3遮掩Base::mf3

    解决办法:使用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();
            ...
    };
    
    Derived d;
    int x;
    ...
    d.mf1(); //仍正确,调用Derived::mf1
    d.mf1(x); //没问题了!调用Base::mf1
    d.mf2(); //仍正确,调用Base::mf2
    d.mf3(); //仍正确,调用Derived::mf3
    d.mf3(x); //没问题了!调用Base::mf3

    -----------------

    有时并不想继承base classes的所有函数,这是可以理解的。但这在public继承下绝不可能发生,∵其违反了public继承所暗示的is-a关系。

    例如,Derived以private形式继承Base,而唯一想继承的mf1是无参版。using声明式技术此时就不行了,∵using声明式会令继承而来的某给定名称之所有同名函数在derived class中都可见。

    此时需要“转交函数”技术:

    class Base {
        public:
            virtual void mf1() = 0;    //仅想继承这个
            virtual void mf1( int );
            ...
    };
    
    class Derived : private Base {  //注意是以private方式继承!!!而非public
        public: //???有点不能理解
            virtual void mf1() { //此为转交函数,暗自inline
                Base::mf1();
            }
            ...
    };
    
    Derived d;
    int x;
    ...
    d.mf1();   //正确,调用Derived::mf1(本质是里面调用Base版!!!)
    d.mf1(x);  //错误!Base::mf1(int)被遮掩了,同时这也达到目的
              //∵我们的目的就是唯一想继承的mf1是无参版

    条款34 区分接口继承和实现继承

    记住:

    ★接口继承和实现继承不同。在public继承下,derived classes总是继承base class的接口

    ★纯虚函数只具体指定接口继承

    ★普通虚函数具体指定接口继承及缺省实现继承

    ★非虚函数具体指定接口继承以及强制性实现继承

    ------------------------------------------------

    一种特殊情形:

    基类的纯虚函数必须在derived classes中重新声明,且基类的纯虚函数在基类中也是可以给出详细定义的,这个定义也可以表现出一种缺省行为(那是derived class可能使用的,但只有在它们明确提出申请时才是)。

    class Airplane {
        public:
            virtual void fly( const Airport &destination ) = 0;        //纯虚!
            ...
    };
    
    void Airplane::fly( const Airport &destination ) { //基类纯虚函数竟也可以提供定义!!!
        //缺省行为
    }
    
    class ModelA : public Airplane {
        public:
            virtual void fly( const Airport &destination ) {
                Airplane::fly( destination ); //derived class须明确提出申请!!!
            }
            ...
    };
    
    class ModelB : public Airplane {
        public:
            virtual void fly( const Airport &destination ) {
                Airplane::fly( destination ); //derived class须明确提出申请!!!
            }
            ...
    };
    
    class ModelC : public Airplane {
        public:
            virtual void fly( const Airport &destination );    //ModelC自己重新定义
            ...
    };
    
    void ModelC::fly( const Airport &destination ) {
        //属于C类型飞机自己特有的飞行方式
    }
  • 相关阅读:
    js判断时间间隔
    redis 常用命令
    Spring 启动 自动调用方法的两种形式
    多线程的异常处理
    多线程Monitor.TryEnter(有一个聪明的员工找老板。看到老板们在里面都掐成一团乱麻了,算了我还是撩吧)
    多线程中多个join的执行过程
    多线程之向线程传递参数
    ASP.Net Core下的安全(授权、身份验证、ASP.NET Core Identity)
    C# 中常用的索引器(转)
    《戏班的故事》C#基础之多线程之“前台线程-后台线程”
  • 原文地址:https://www.cnblogs.com/hansonwang99/p/4961298.html
Copyright © 2020-2023  润新知