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类型飞机自己特有的飞行方式
}
原文地址:https://www.cnblogs.com/hansonwang99/p/4961298.html