zoukankan      html  css  js  c++  java
  • Effective C++ -- 继承和面向对象设计

    32.确保你的public继承了模is-a关系

    public继承意味着is-a关系(里氏替换原则),一切适用于基类也适用于派生类。
    矩形继承正方形问题:

    • 可实施与矩形的操作无法实施与正方形
    • 在编程领域。正方形是一种矩形是错误的
    • 在现实领域,正方形是一种矩形是正确的

    33.避免遮盖继承而来的名称

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

    继承类函数会遮掩基类的同名函数。即使參数不同。
    目的是防止继承类从基类继承重载函数。

    解决方法例如以下:

    class Derived:public Base {
    public:
        using Base::mf1;// 让Base class内mf1的全部东西在继承类作用域中都可见
        using Base::mf3;
        virtual void mf1();
        void mf3();
        void mf4();
    };

    为了让遮掩重见天日。可使用using声明式或者转交函数。

    34.区分接口继承和实现继承

    1. 接口继承
    2. 接口和实现继承,同一时候覆写
    3. 接口和实现继承。不覆写
    class Shape {
    public:
        virtual void draw() const = 0;// 接口继承
        virtual void error(const string& msg);// 接口和实现继承。同一时候覆写
        int object() const;// 接口和实现继承,不覆写 
    };

    同意impure virtual函数同一时候指定函数声明和函数缺省行为。可能造成危急。


    类A提供纯虚函数及实现fly()。期望继承类B使用fly实现,继承类C不使用fly实现。C类的实现者可能不清楚这一约定,造成类C也使用fly的实现。


    解决方法:
    1. 将fly改为纯虚函数。类A中实现protected defaultfly。

    类B实现fly中调用defaultfly。类C实现fly。
    2. 将fly改为纯虚函数,类A中提供fly的定义,类B实现的fly中调用A::fly(),类C实现fly

    结论:

    • 声明为纯虚函数期望继承类仅仅继承接口。
    • 声明为虚函数目的是让继承类继承该函数的接口和缺省默认实现
    • 声明为非虚函数目的是让继承类继承函数的接口和一份强制的实现

    35.考虑virtual函数以外的其它选择

    • NVI Non-Virtual Interface用来替代public virtual的方案
    • 由Function Pointers实现strategy模式
    • 古典策略模式
      遗留问题:
      tr1::function使用

    36.绝不又一次定义继承而来的non-virtual函数

    non-virtual代表不变性凌驾与特异性。

    目的是令继承类继承函数的接口及一份强制实现
    使用基类指针会调用到基类的版本号

    37.绝不重定义继承而来的缺省參数

    非虚函数中不同意在继承类中重定义
    在虚函数中更改继承类的缺省參数不会起作用
    虚函数中更改缺省參数不起作用的原因,出于效率考虑,在运行期确定參数比编译器决定慢且更为复杂
    虚函数中不要提供缺省參数,虚函数改动缺省參数后,继承类要跟着改动
    使用NVI(non-virtual infterace方法。non-virtual方法中提供缺省參数,no-virtaul方法调用virtual方法)

    class Shape {
    public:
        enum ShapeColor {Red,Green,Blue};
        void draw(ShapeColor color = Red) const {
            doDraw(color);
        }
    private:
        virtual void doDraw(ShapeColor color) const = 0;
    };
    class Rectangel:public Shape {
    private:
        virtual void doDraw(ShapeColor color) const;
    };

    38.通过复合塑模出has-a或“依据某物实现出”

    复合的两层含义

    • has-a(应用域对象,比如汽车,视频画面)
    • is-implemented-in-terms-of(实现域,比如缓存器。相互排斥器)

    39.明智而审慎地使用private继承

    • 假设是private继承,须要基类对象的场合。传入继承类错误,编译器不会自己主动将继承类对象转换为一个基类对象。
    • 由private继承而来的全部成员,在继承类中都会变为private
    • private继承意味着implemented-in-terms-of(依据某物实现)
    • 继承类和基类没有不论什么关系
    • private继承意味着实现被继承,接口部分被略去。private继承在设计层面没有意义
    • 和复合之间的取舍
      • 尽可能使用复合
      • 须要改动private继承基类中的虚函数时使用私有继承
      • 替代私有继承须要更改虚函数的还有一种方法: 使用复合,复合类中定义一个public继承的嵌套类,复合类使用该嵌套了的对象。
    class Widget {
    private:
        class WidgetTimer:public Timer {
        publicvirtual void OnTick() const;
        };
        WidgetTimer timer;
    }; 

    以上方式也能够用来阻止继承类又一次定义virtual函数

    • 使用private的还有一个场合:EBO empty base optimization空白基类最优化(STL中使用 unary_function,binary_function)

    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    python 多线程实例
    手把手教你做酷炫的数据可视化大屏,零基础的你仅需6步
    化繁为简:数据库运维人员应该知道这些...
    凭什么它能成为报表神器?这五大技术硬货不得不服
    《算法图解》学习笔记(九):动态规划(附代码)
    前端布局总结(持续更新)
    前端布局总结(持续更新)
    前端布局总结(持续更新)
    前端布局总结(持续更新)
    linux之centos安装jdk以及nginx详细过程
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4668355.html
Copyright © 2011-2022 走看看