美文网首页
Effective C++ 6: Inheritance & O

Effective C++ 6: Inheritance & O

作者: my_passion | 来源:发表于2021-07-22 23:20 被阅读0次
        OOD:    Object Oriented Design
    
        1   `理解 C++ 各种 特性` 的 `真正意义`, 才能 `通过 C++ 特性, 说出 你对 软件系统 的 想法`
    
            ————————————————————————————————————————————————————
                                 |      意味着 
            ————————————————————————————————————————————————————                
            [1] public 继承    |      is-a 关系 
            ————————————————————————————————————————————————————                
            [2] virtual 函数   |  `接口 必须 被继承`
            ————————————————————————————————————————————————————                
            [3] non-virtual 函数 |    `接口 和 实现 都必须 被继承`
            ————————————————————————————————————————————————————
            
            ——————————————————————————————————————————————————————————————————————
        2   3 种继承           |   意义
            ——————————————————————————————————————————————————————————————————————
            [1] public 继承       |   is-a 
            ——————————————————————————————————————————————————————————————————————
            [2] private 继承      |   is-implemented-in-terms-of + 不允许 进一步派生
                                |       据某物实现出
            ——————————————————————————————————————————————————————————————————————
            [2] protected 继承    |   is-implemented-in-terms-of +   允许 进一步派生 
            ——————————————————————————————————————————————————————————————————————
    
        3   class 间 关系
    
            ——————————————————————————————————————————————
            [1] is-a
            ——————————————————————————————————————————————
            [2] has-a (有一个) // 7 / 8 节
            ——————————————————————————————————————————————
            [3] is-implemented-in-terms-of // 7 / 8 节
            ——————————————————————————————————————————————
    

    1 public 继承 要 model 出 is-a 关系

        1   `OOP 最重要的 规则
    
            `public 继承` 意味着 `is-a (是一种)` 关系
    
                `LSP:   Liskov 替换原则`
                
                    Derived `public 继承` Base
                    
                        则 `需要 Base 对象 ( ptr/ ref ) 的地方, Derived 对象 ( ptr / ref ) 一样可以效劳`
                            
                            反之不然
    
                                原因: `每个 Derived 对象 都是一种/个 Base 对象`
                                    
                                    反之不然
    
                    `函数 若 期望 arg 为 Base ( ptr/ref ), 也都愿意 接受 Derived 对象 ( ptr/ref )` 
                
        2   public 继承 和 is-a 的 `等价关系 并不像 直觉那么简单`
    
            `2 个例子`
    
            (1) `鸟 和 企鹅`
    
                1) `双 class 继承体系`
                        |
                        |   语法正确, 但 没 model 出 真实性`
                        |                 |\
                        |/                |
                    企鹅 is-a 鸟          |
                              |           |
                              |/          |
                            鸟会飞 => 企鹅会飞
                                |
                                |   我们说 鸟会飞 时,
                                |/
                            `真正意思` 是一般 `会飞的鸟`, 但有数 `不会飞的鸟`
    
                2)  `3 class 继承体系: model 出 真实性`
    
                                  鸟:    没声明 fly() 
                                 /   \
                                /     \
                               /       \
                        会飞的鸟        企鹅/不会飞的鸟 
                            |
                            |
                            |/
                        声明 fly() 
    
                3) `但, 某些 软件系统, 不打算 对飞行 "有所知"`, 则 `无需区分`
                
                        会飞和不会飞 的鸟
    
                            => `双 class 继承体系` 更好
    
                4) `编译期/运行期 拒绝` 企鹅 fly` 的 设计: 前者优
    
                        ——————————————————————————————————————————————————————————————————————————————————————————————
                                        |       实现                          |   含义
                                        |                                       |
                                        |   鸟 类 & 企鹅 类                      |   
                        ——————————————————————————————————————————————————————————————————————————————————————————————  
                        [1] 运行期报错   |   均   声明 fly() 为 vf               |   企鹅会飞, 但尝试那么做 是一种错误
                                        |                                       |
                                        |       但 企鹅 类 fly() 中调 `报错函数`|
                        ——————————————————————————————————————————————————————————————————————————————————————————————          
                        [2] 编译期报错   |   均 不声明 fly()                     |   企鹅不会飞
                        ——————————————————————————————————————————————————————————————————————————————————————————————
    
            (2) 长方形 和 正方形
                
                    `适用于 Base 的 事, 却 不适用于 Derived 身上`
                            |                       |
                            |   Rectangle           |   Square
                            |/                      |/
                        `长 可 独立于 宽 被修改: makeBigger()`
                            
                            而 `public 继承 主张, 适用于 Base 的事, 一定适用于 Derived`
    
                                => `以 public 继承 model Rectangle 与 Square 的关系 并不正确
                                        
                                        compile 会通过, 但 程序 behavior 不对`
    

    2 避免 hide inherited name

        1   `内层 scope 会 hide 外围 scope 的 相同 name`
    
        2   引入 `继承`
            
                [1] `Derived 内 hide ( => 看不到 ) Base` 内 `相同 name`
    
                    `按 name 查找, 与 para / return type / 是否 virtual 等 无关`
                        
                [2] `欲 继承 base 的 同 name 重载函数`
                        
                        `using 声明` 
                            
                            使 Base 内 `所有` 该 `name 在 Derived 内 可见`
    
                [3] 欲 继承 + `override 部分 同 name 重载函数`
                    
                        `转交函数 ( forwarding function )`
                            
                            Derived vf 调用 `Base名 限定 的 Base vf`
                            
                                virtual void Derived::vf() { Base::vf(); }
    

    3 区分 接口继承实现继承

        0    概述
    
            (1) `override ( 覆写 ) = redefine ( 重新定义 )`
                ——————————————————————————————————————————————————————————————
                override 可用
                    ——————————————————————————————————————————————————————————
                    [1] `different implement`
                    
                    [2] `same implement` ( as base ): `转调 base 的 缺省实现`
                ——————————————————————————————————————————————————————————————
            (2) public 继承` 下 `pure vf (pvf) / impure vf / non-vf`
    
                public 继承
                
                    function `interface/implement  继承`
                    
                        像 函数 `声明 / 定义` 的 差异
                        
                    含义: is-a
                    
                        interface (of mem func) 总是会被 继承
                        
                        某 mem_func 可用于 Base 上, 一定也能 用于 Derived 上
    
                class 设计者 据不同需求, 可能希望 derived class
                    ————————————————————————————————————————————————————————
                    1   只继承 interface ( 即 declaration ) of mem func
                        
                        必须 override implement
                            
                            `pvf`
                    ————————————————————————————————————————————————————————
                    2   继承 interface 和 default implement ( 缺省实现 )
                        
                        希望但 不强迫 override
                            
                            `impure vf`
                    ————————————————————————————————————————————————————————
                    3   继承 interface 和 `强制性实现` 
                                            |
                                            |/
                                        不允许 override
                            
                            `non-vf`
                    ————————————————————————————————————————————————————————
        1    pvf
    
            (1) 目的 
    
                只继承 `interface` 
                    
                    => 必须 override`
    
            (2) 特点
    
                [1] pvf 使 其所在 class 成为
    
                    `abstract (抽象) class`
    
                        而 client 不能 new abstract class object
                        
                            只能 new 相应的 derived class object
    
                [2]  `pure vf 可 define`, 但 `唯一 调用方法` 是 `用 class name 限定`
    
            (3) 应用
    
                `为 impure vf 提供` 更 safe 的 `缺省实现`
    
        2   impure vf
    
            (1) 目的
            
                继承 `interface 和 缺省实现`
                        
                    => `希望 但 不强制 override`
    
            (2) 典型 OOD: 1种 重构手法
    
                2 class `共同 性质` 提取到 Base, `继承` 以 `避免 code 重复`
                            |
                            |   如 `飞行方式` 
                            |/
                          fly()
    
            (3) 第 3 种 飞机: `飞行方式` 不同
    
                思路
                
                    `切断 ( Derived ) vf interface` 与其 `( Base ) 缺省 implement 间` 的 `连接`
                    
                        ——————————————————————————————————————————————————————————
                        [1] 方法 1
                            ——————————————————————————————————————————————————————
                            1] Base::pvf    不定义 
                                                |
                                                |/
                                        改用 non-vf: define default impl
                                                |
                                                |/
                                            protected
                                                |
                                                |/
                                            给 Derived 用
                            ——————————————————————————————————————————————————————
                            2] Derived::vf          
                                ——————————————————————————————————————————————————                  
                                同性质   Derived   |   override: 调 Base::non-vf
                                ——————————————————————————————————————————————————
                                独特性质 Derived    |   override: 新实现
                        ——————————————————————————————————————————————————————————
    
                        ——————————————————————————————————————————————————————————
                        [2] 方法 2    
                            ——————————————————————————————————————————————————————
                            1] Base::pvf            |   define default impl
                            ——————————————————————————————————————————————————————
                            2] Derived::vf          
                                ——————————————————————————————————————————————————                   
                                同性质   Derived   |    override: 转调 Base::pvf
                                ——————————————————————————————————————————————————
                                独特性质 Derived    |    override: 新实现
                        ——————————————————————————————————————————————————————————
                        
                    比较
    
                        [1] pvf ( fly ) 分割为 2 部分  
                                
                                `接口`       ( 声明部分, Derived 必须使用 )  
                                 |
                                 |/
                                pvf 
                                
                                `缺省实现` ( 定义部分, Derived 明确要求时才使用 )
                                    |
                                    |/
                                non-vf 
                                
                            好处: 让 `接口 函数` 和 `缺省 实现函数` 享有 不同保护级别 public / protected
                                
                        [2] 合并 `接口 函数` 和 `缺省 实现函数` 
            
        3   non-vf
    
            (1) 目的
    
                    继承 `interface 和 强制实现` 
                                        |
                                        |/
                                    => 不允许  override`
    
            (2) 意义
    
                `不变性 ( invariant ) 凌驾 特殊性 ( specialization ) 之上 
                    
                    即 `non-vf 不打算 在 derived class 中 有 不同行为`
    
                        derived class 本身 可 特殊化, 但 
                            
                            `non-vf 指定的 行为不可改变`
    
                                =>  不该在 derived class 中 override
    

    4 考虑 vf 之外 的 选择

        1   `NVI` 手法 实现 `Template Method`
              |
              |
            non-virtual interface
            
            `NVI` ( func ) `wrap 访问性更低` 的 `vf`  
             |                          |         |
             |                          |         |
            public          private/protected    做实际工作 
    
            (1) 优点
    
                wrapper/nvi 可使在 `vf 调用 前/后`
                
                    [1] 设定适当场景
                        lock a mutex / log entry / 验证 class 约束条件
                        
                    [2] 清理场景
                        unlock a mutex / 验证 class 约束条件
        
        2   用 `fp` ( function pointer ) 实现 `Strategy` 模式
        
            `non-mem function pointer 作 mem data
                        |
                        |/
                    para 为 class 的 const 引用
    
            (1) `Strategy 模式`
                
                [1] pf (pointer to function) mem
                
                [2] ctor: receive & store 传入的 pf (策略) 到 pf mem
                
                [3] non-vf 用 pf mem 调 func(策略): *this 作 arg
                
    
            (2) `相对于 A 内 vf 的 优点`
    
                [1] `不同 A object` 可拥有 `不同 策略函数`
    
                [2] `运行期 可改变 策略函数`
    
            (3) 缺点
                
                `class 封装性 降低`
    
        3   泛化
                    
                                                std::bind(&B::f3, b, _1)
                                                    |\
                                                    |   _1: 调用 &B::f3 时, 以 b 作 对象
                                                    |
                                                    |
            [1] `std::function 对象` 可持有 `任何 可调用对象`
                    
                只要 `其 签名式 ( signature )` 兼容于 `需求端`
                                                |
                                                |
                                                |/
                                            可调用对象 的 函数调用运算符 returnType `可 隐式转换为 signature 的 returnType`
                        
            [2] 与 2 相比 
            
                实现上( 仅 1 点 )
                
                    普通 `函数指针 类型别名` 
                            |
                            |   换为
                            |/
                        策略 `std::function 类型` 别名
                            typedef std::function<int (const A&)> PF;       
                    
                class A; // 前向声明
                int defaultPF(const A&);
    
                class A
                {
                public:
                    // [1] 策略 std::function 类型 `别名` 
                    typedef std::function<int (const A&)> PF;
                    
                    // [3] 
                    explicit A(PF pf_ = defaultPF)
                        : pf(pf_) {}
                    
                    / [4]
                    int nvf() const { return pf(*this); }
                private:
                    PF pf; // [2] 
                };
    
                // 1) function
                short f1(const A&);
    
                // 2) function object
                struct F2
                {
                    int operator()(const A&) const { return 1; }
                };
    
                // 3) mem func
                class B
                {
                public:
                    float f3(const A&) const; // mem func
                };
    
                class A1: public A // 同2
                {
                    /* .. */
                };
    
                // --- client
                A1 person1(f1);
                A1 person2(F2() );
    
                B b;
                A1 person3( std::bind(&B::f3, b, _1)  );
    
        4   `委托` 给 `另一 继承体系` 的 `vf`
    
            `经典 Strategy 模式`
                
                与 3 相比 
                    
                    [1] 策略 `std::function 类型` 别名` 
                                |
                                |   换为 
                                |/
                            `策略 函数对象` 
                                            含 vf  
                                             |\
                                             |  调  => `多态 即 多策略`
                                             |
                    [2] 模板类 Ctor 参数: `策略函数对象 指针` 
                
                
                class A; // 前向声明
    
                class PF                                       // [1]
                {
                public:
                    virtual int vf(const A& c) const 
                        { /* ... */ }
                };
                
                PF defaultPF; 
    
                class A
                {
                public:
                    explicit A(PF* pf_ = &defaultPF)            // [3]
                        : pf(pf_) {}
                        
                    int nvi() const { return pf->vf(*this); }   // [4]
                private:
                    PF* pf;                                     // [2]
                };
    
    1.jpg 2.jpg 3.jpg

    5 绝不 redefine 继承而来non-virtual func: 设计上 矛盾

    non-vf: non-virtual mem func
    
        1   `业务角度`
    
            non-vf 调用 是 
                
                静态绑定
                    
                    `non-vf 通过 ptr/ref 被调用` 时, 
                        
                        表现的 `行为 取决于` 指向 object 的 `ptr/ref 的 type`
    
        2   `设计角度`
        
            [1] public 继承 意味着 is-a
            
            [2] non-vf 声明 
            
                `为 class 建立 不变性/invariant, 凌驾 其 specialization`
    
            => `若 redefine 继承而来` 的 `non-vf`,
                    
                    则 上述两者在 `设计上 就 矛盾了`
    

    6 绝不 redefine 继承而来 的 vf 的 默认参数值

        1   
            ——————————————————————————————————
            [1] ptr/ ref 调 vf       动态绑定
            ——————————————————————————————————
            [2] object   调 vf   静态绑定
            ——————————————————————————————————
            [3] 缺省参数值           静态绑定        
            ——————————————————————————————————
            
                            取决于 `ptr/ref 所指 object` 的 `运行期 type`
                              |\
                              | 是 Base::vf 还是 Derived::vf 
                              |
            (1) `动态绑定 调 vf` 
                
                    vf `才` 从 base class 继承 `缺省参数`
                                                |
                                                |   是 静态绑定
                                                |
                                                |   用的是 Base::vf 还是 Derived::vf 中的 缺省参数 
                                                |/
                                            取决于 ptr / ref 的 type    
    
            (2) `override` vf `默认参数值` 的 `问题`
    
                —————————————————————————————————————————————————————————————————
                Base ptr 
                    —————————————————————————————————————————————————————————————
                    [1] 指向 Derived object
    
                    [2] 调 vf 
                        Derived::vf / Base::vf 默认参数值 不同
                    —————————————————————————————————————————————————————————————       
                    => `override` vf `默认参数值`
    
                    => `vf code 用 Derived 内那份, 但 默认参数值 用 Base 内那份`
                            
                            即, `Base 和 Derived 的 vf 声明式 各出一半力`
    
                                B* pr = new D;  // pr 静态类型为 B*
                                pr->vf(B::Color color = Green);  // D::vf(B::Color color = Red )
                —————————————————————————————————————————————————————————————————
    
        2   `若 遵守本规则`, `又想提供 缺省参数值` 给 Base 和 Derived 用户 
                
                [1] Base
                
                    1] `NVI: non-vf 指定 缺省参数` 
                                |
                                |/
                            绝不应该被 override 
                                
                                => 缺省值 总是 Base 中 版本 
                        
                    2]  调 `private pvf 负责 真正工作`
                    
                [2] Derived 
                    
                    impure vf override Base::pvf 
                    
                [3] Base ptr/ref
                    
                    1]  指向 Derived 对象 
                    
                    2]  调 non-vf ( 继承而来的 )
    

    7 用 composition 建模 has-a ( 有一个 ) / is-implemented-in-terms-of ( 据某物实现出 )

        1   `Composition 2 层含义`                                 class A{
                    |                                               private:
                    |/                                                  std::string name;
                是 `类型 间 关系: 类型1 对象 内含 类型2 对象`           B b;    class B { /* ... */ };
                                                                    };
                `composition` 发生于 
                    
                    `应用域 / 实现域 object 间`,
                        
                        表现出 `has-a / is-implemented-in-terms-of` 关系
                
                        
                            ——————————————————————————————————————————————————————————————
                            软件中 处理 2个领域             |
                            ——————————————————————————————————————————————————————————————
                            应用域: 所塑造的世界 中 的事物   |   人 / 汽车
                            ——————————————————————————————————————————————————————————————
                            实现域: 实现细节               |   buffer / mutex / rbtree
                            ——————————————————————————————————————————————————————————————
    
        2   应用: 用 std::list 实现 set
    
            需求: 需 template, 造出 一组 class 表现 `不重复对象 组成的 set`
    
            (1) 方法 1: 用 std::set 
            
                [1] `空间 比 速度 重要 时 -> std::set 不合理`
                
                [2] 速度 比 空间 重要 时 -> std::set 合理
    
            (2) 方法 2: public 继承 std::list
    
                template<typename T>
                class Set: public std::list<T>{...};
    
                问题
                    Set 与 std::list 用 is-a 关系 不合适
                        list 内 元素 可重复
                        
                        Set  内 元素 不可重复
                                        
            (3) 方法 3: Set 与 std::list 用 Composition 关系
    
                Set is-implemented-in-terms-of std::list
                
                    熟悉 STL, 则 很容易实现 
    
                        template<typename T>
                        class Set
                        {
                        private:
                            std::list<T> rep; // 用来 表述 Set 的 data           
                        public:
                            // ...
                        };
                        
                        template<typename T>
                        void Set<T>::insert(const T& item)
                        {
                            if( ! is_member(item) )
                                rep.push_back(item);
                        }
    

    8 慎用 private 继承

        1   `private 继承` 的 `行为 & 意义`
    
            (1) 行为
    
                private 继承 下
    
                    `compiler 不会` 自动 `将 derived class 对象 转换为 base class 对象`
    
            (2) 意义
                
                只在 `软件实现层面 有意义`, 在 `软件设计层面` 没有意义
                    
                    [1] is-implemented-in-terms-of ( 据 某物 实现出 )`
                                                         |
                                                         |/
                                                        Base
                                                        
                    [2] 只有 `implement 部分 被继承, interface 部分 应略去`
    
        2   `private vs. Composition`
    
                意义都是 is-implemented-in-terms-of
    
                (1) 两者 怎么选 ?
    
                    尽可能 用 Composition
                        
                        `必要时` 才用 private 继承
                `           |
                            |   `何时才必要 ?`
                            |/
    
                        3 种情形
    
                            2 个 class (A 和 B) `不存在 is-a 关系` 
                                
                                而是 is-implemented-in-terms-of 关系 时
                            
                                    —————————————————————————————————————————————
                                    [1] A 需 `访问`     B 的 `protected 成员` 
                                    —————————————————————————————————————————————
                                    [2] A 需 `override` B 的 vf
                                    —————————————————————————————————————————————
                                    [3] `empty base 最优化`
                                    —————————————————————————————————————————————
                            
        3   is-implemented-in-terms-of 的 3 种实现
    
            需求
    
                需 `实现类 (定时器 Timer)`
    
                    `可按 任何频率 滴答, 每次滴答 调某 vf`
    
                        让 `目标类` 可以 override `实现类` 的 vf
                                            |
                                            |   目的
                                            |/
                                        访问 `目标类` 的 data 
                                            
            [1] private 继承
    
                public 继承 不合适
                
                    Widget isn't a  Timer
                
            [2] `( private 区 ) Composition + public 继承`
                
                1] `成员类` public 继承 `实现类`  
                      |                     |
                      |                     |
                      |/                    |/
                    WidgetTimer         Timer
                        |
                        |/
                        放 private 区
                            
                    =>  `目标类` definition 必须 可见 `实现类` definition
                            |                     |
                            |                     |
                            |/                    |/
                         Widget             #include "实现类 定义 头文件"
                                    
                            =>  目标类  `依赖` 实现类 
            
                2] 据 `成员类` 实现 override `实现类` 的 vf`
    
                ——————————————————————————————————————————————————————————————————————————
                [2] 与 [1] 相比 
                    ——————————————————————————————————————————————————————————————————————
                    若想 从 目标类 `进一步派生` 
                        
                        又想 `阻止` 派生出的类 `override 成员类型 的 vf`
    
                            只能用 [2], 不能用 [1]
                ——————————————————————————————————————————————————————————————————————————
                                原因
                                    1]  private 继承 ( [1] ) => `阻止了 目标类 进一步派生` 
                                ——————————————————————————————————————————————————————————
                                    2]  ( private 区 ) Composition + public 继承 ( [2] )
                                
                                        =>  `派生出的类` 无法取用 `成员类型` 
                                                            
                                            => 无法 `override 成员类型 的 vf`
                ——————————————————————————————————————————————————————————————————————————
    
            [3] `成员类型` 变 `成员(类型)指针`
                
                `成员类` 
                    
                    1] 本身 `移出` 
                    
                    2] 替换为 `其 指针`
                    
                            `目标类` 只需带 `成员指针 相应类型` 的 declaration
                                |                           |
                                |/                          |/
                            Widget                      WidgetTimer
                ——————————————————————————————————————————————————————————————————————              
                [3] 与 [2] 相比 
                    ——————————————————————————————————————————————————————————————————
                    1] 优势   |   目标类 `编译依赖 降低` 
                    ——————————————————————————————————————————————————————————————————   Note
                    2] 代价   |   目标类 `无法 override 成员(类型)指针 相应类型` 的 vf  - - - - -> 只是不符合 需求 中的 override
                ——————————————————————————————————————————————————————————————————————
                
        4   empty base 最优化
    
            (1) `empty base`
    
                无
                    non-static 成员变量
                    vf
                    virtual base class
    
                往往含
                    static 成员变量
                    non-virtual func
                    typedef
                    enum
    
                ———————————————————————————————————————————————————————
                C++ 规定
                
                    `empty class` 
                        ———————————————————————————————————————————————
                        [1] `独立 对象` 都 `必须有 非0 大小`
                            大多 compiler 做法:
                                Empty class 插 一块足够放 int 的 空间
                        ———————————————————————————————————————————————
                        [2] 作 成员对象 
                            不占空间 
                ———————————————————————————————————————————————————————
    
            (2) `EBO / empty base optimization: private 继承 Empty class`
    
                `优势: 不增加 Derived class 大小`
                
                    [1] EBO 一般只在 单继承 下 可行
    
                    [2] STL 中 empty base, 通常内含 typedef
                
                        unary_function / binary_function
    

    9 慎用 多重继承

        1   多重继承 
        
            [1] 问题1
    
    
                class A public 继承 class B 和 C
                    
                    `通过 class A 对象 调 B 和 C` 的 `同名 mem func` 
    
                        二义性 
                            |
                            |   解决 
                            |/
                        class B/C name 限定
    
            [2] 问题 2
    
                `菱形继承` 
                    
                    `最远基类 的 mem data 在 最远派生类 中 有 2 份`
                        |
                        |   解决 
                        |/
                    `virtual 继承`
    
        2   virtual 继承
    
            (1) `3 代价` ( 相比于 non-virtual 继承 )
    
                1) class 占用空间 更大
    
                2) 访问 virtual base class 的 成员变量, 访问速度更慢
    
                3) `virtual base class 初始化` 每个 `继承它的 class 都要负责`
    
            (2) 忠告
            
                1) 非必要 不要用 virtual base class
    
                2) 若必须用 virtual base class, 尽量 `避免在其中 放 data`
                
        3   `ImplementClass: public 继承 Interfaceclass  + private 继承 ImplementInfoClass`
                    |                                       |
                    |   中                                   |/
                    |                   可替换为 `( private 区 ) Composition + public 继承`
                    |/
                可用 Factory Method `创建 ImplementClass 对象`
                    
                    // Factory Method
                    std::shared_ptr<IPerson> 
                        makePerson(DatabaseId personId);
    
                    // client 
                    std::shared_ptr<IPerson> spIP( makePerson(id) );
                    
                        // 辅助函数 
                        DatabaseId id(askUerForDatabaseId() );
                        
                            DatabaseId askUerForDatabaseId();
    
    public 继承 + Composition.jpg
    === 详细 
    

    1 public 继承 要 model 出 is-a 关系

        1   `OOP 最重要的 规则
    
            `public 继承` 意味着 `is-a (是一种)` 关系
    
            `Liskov 替换原则`
            
                Derived `public 继承` Base
                
                    则 `需要 Base 对象 ( ptr/ ref ) 的地方, Derived 对象 ( ptr / ref ) 一样可以效劳`
                        
                        反之不然
    
                            原因: `每个 Derived 对象 都是一种/个 Base 对象`
                                
                                反之不然
    
                `函数 若 期望 arg 为 Base ( ptr/ref ), 也都愿意 接受 Derived 对象 ( ptr/ref )` 
                
                    // 学生 和 人 的例子
                    class Person { ... };
                    class Student: public Person { ... }
                    void eat(const Person& p);
                    void study(const Student& s);
    
        2   public 继承 和 is-a 的 `等价关系 并不像 直觉那么简单`
    
            `2 个例子`
    
            (1) `鸟 和 企鹅`
    
                1) `双 class 继承体系`
                        |
                        |   语法正确, 但 没 model 出 真实性`
                        |                 |\
                        |/                |
                    企鹅 is-a 鸟          |
                              |           |
                              |/          |
                            鸟会飞 => 企鹅会飞
                                |
                                |   我们说 鸟会飞 时,
                                |/
                            `真正意思` 是一般 `会飞的鸟`, 但有数 `不会飞的鸟`
                        
                        
                            class Bird
                            {
                            public:
                                virtual void fly(); // 鸟会飞
                            };
    
                            class Penguin: public Bird
                            {
                                // ... //  企鹅会飞: not real
                            };
    
                2)  `3 class 继承体系: model 出 真实性`
    
                                  鸟:    没声明 fly() 
                                 /   \
                                /     \
                               /       \
                        会飞的鸟        企鹅/不会飞的鸟 
                            |
                            |
                            |/
                        声明 fly() 
    
    
                    class Bird
                    {
                        ... // 没声明 fly()
                    };
    
                    class FlyingBird: public Bird
                    {
                    public:
                        virtual void fly();
                    };
    
                    class Penguin: public Bird
                    {
                        ... // 没声明 fly()
                    };
    
                3) `但, 某些 软件系统, 不打算 对飞行 "有所知"`, 则 `无需区分`
                
                        会飞和不会飞 的鸟
    
                            => `双 class 继承体系` 更好
    
                4) `编译期/运行期 拒绝` 企鹅 fly` 的 设计: 前者优
    
                        ——————————————————————————————————————————————————————————————————————————————————————————————
                                        |       实现                          |   含义
                                        |                                       |
                                        |   鸟 类 & 企鹅 类                      |   
                        ——————————————————————————————————————————————————————————————————————————————————————————————  
                        [1] 运行期报错   |   均   声明 fly() 为 vf               |   企鹅会飞, 但尝试那么做 是一种错误
                                        |                                       |
                                        |       但 企鹅 类 fly() 中调 `报错函数`|
                        ——————————————————————————————————————————————————————————————————————————————————————————————          
                        [2] 编译期报错   |   均 不声明 fly()                     |   企鹅不会飞
                        ——————————————————————————————————————————————————————————————————————————————————————————————
                        
                            void error(const std::string& msg);
    
                            class Penguin: public Bird
                            {
                                virtual void fly() { error("attempt to make a penguin fly"); }
                            };
    
                            Penguin p;
                            p.fly(); // [1] 运行期 报错  
                                |
                                |
                                |/
                            class Bird
                            {
                                // ... // 没声明 fly()
                            };
    
                            class Penguin: public Bird
                            {
                                // ... // 没声明 fly()
                            }
    
                            Penguin p;
                            p.fly(); // [2] 编译期 报错
    
            (2) 长方形 和 正方形
                
                    `适用于 Base 的 事, 却 不适用于 Derived 身上`
                            |                       |
                            |   Rectangle           |   Square
                            |/                      |/
                        `长 可 独立于 宽 被修改: makeBigger()`
                            
                            而 `public 继承 主张, 适用于 Base 的事, 一定适用于 Derived`
    
                                => `以 public 继承 model Rectangle 与 Square 的关系 并不正确
                                        
                                        compile 会通过, 但 程序 behavior 不对`
    
    
                    class Rectangle
                    {
                    public:
                        virtual void setLength(int length_);
                        virtual void setWidth(int width_);
                        virtual int length() const;
                        virtual int width() const;
                    };
    
                    void makeBigger(Rectangle& r)
                    {
                        int old_length = r.length();
                        r.setWidth( r.width() + 10 );
                        assert( r.length() == old_length );
                    }
    
                    上述 assert 永远为真
    
                    class Square: public Rectangle { ... }
                    Square s;
                    ...
                    assert(s.length() == s.width() ); // 对正方形 一定为真
                    makeBigger(s); // s is-a Rectangle
                    assert(s.length() == s.width() ); // 问题
    
        3   题外话
    
            (1) `并不存在 完美设计` 以 适用于 所有软件
                
                    `最佳设计 取决于 系统` 现在和未来 `希望做什么事`
    
            (2) 你的 `设计` 军械库 加上了 `继承` 这门大炮, 你也必须 `为 你的直觉 增加 新的 洞察力`
    
                    当某天 有人让你看1个长达数页 的 函数 时, 你终将回忆起 
                        `令 Penguin 继承 Bird, 或 令 Square 继承 Rectangle` 的趣味;
                            这样的 继承 有可能 接近事实, 也有可能不`
    

    2 避免 hide inherited name

    1.jpg 2.jpg 3.jpg 4.jpg 5.jpg
        1   `内层 scope 会 hide 外围 scope 的 相同 name`
    
            int x;          // global 变量
    
            void someFunc()
            {
                double x;   // local 变量, 为 int 仍 hide
                std::cin >> x;
            }
    
        2   引入 继承
    
            derived class 内 mem func 
            refer to base class 内 某物 ( mem func / typedef / mem data ) 时,
            compiler 可找出 所 refer to 的 东西
    
            (1) `Derived 内 能看到 Base` 内 `不同 name`
    
                compiler: name 匹配查找过程
                
                ——————————————————————————
                [1] local scope  
                [2] 外围 / Derived scope 
                [3] 再外围 / Base scope 
                [4] 再 外围 / global scope
                ——————————————————————————
    
                void Derived::mf4()
                {
                    mf2();
                }
    
            (2) `目标 是 避免 name 问题`
                            
                    而不是 了解 compiler 详细 name 查找规则 
                            
                `Derived 内 hide ( => 看不到 ) Base` 内 `相同 name`
    
                    `按 name 查找, 与 para / return type / 是否 virtual 等 无关`
    
                    // Derived 内 hide 了 Base 内 mf1 mf3
                    Derived d;
                    int x;
                    // ...
                    d.mf1();  // 调 Derived::mf1()
                    d.mf1(x); // error: Derived::mf1 hide 了 Base::mf1
                    d.mf3(x); // error: Derived::mf3 hide 了 Base::mf3
    
            (3) `欲 继承 base 的 同 name 重载函数`
                    
                    `using 声明` 
                        
                        使 Base 内 `所有` 该 `name 在 Derived 内 可见`
    
                    d.mf1(x); // 调 Base::mf1
                    d.mf3(x); // 调 Base::mf3
    
            (4) 欲 继承 + `override 部分 同 name 重载函数`
                
                    `转交函数 ( forwarding function )`  
    

    3 区分 接口继承实现继承

        1    pvf
    
    
                    // 令 pure vf draw 有 定义
                    Shape* ps = new Rectangle;
                    ps->draw(); 
                    ps->Shape::draw();
    
        2   impure vf
    
            (1) 前2种飞机: `飞行方式` 同
                    class Airport { ... };
    
                    class Airplane
                    {
                    public:
                        virtual void fly(const Airport& dst);
                    };
                    void Airplane::fly(const Airport& dst) {    /* 缺省 code */ }
    
                    class ModelA: public Airplane {  /* 可 不声明 fly */ };
                    class ModelB: public Airplane {  /* 可 不声明 fly */ };
    
            (2) 第 3 种 飞机: `飞行方式` 不同
            
                    // ====== solution1:
                    class Airport { /* ... */ };
    
                    class Airplane
                    {
                    public:
                        virtual void fly(const Airport& dst) = 0; // 无法 define      
                    protected: // note
                        void defaultFly(const Airport& dst);      // 改用 non-vf ( protected ): define default impl
                    };
    
                    void Airplane::defaultFly(const Airport& dst)
                    {
                        // 缺省 行为
                    }
    
                    // --- same 性质: 2 个 class
                    class ModelA: public Airplane
                    { 
                    public:
                        virtual void fly(const Airport& dst) { defaultFly(dst); } // override: 调 Base::non-vf 
                    };
    
                    class ModelB: public Airplane
                    { 
                    public:
                        virtual void fly(const Airport& dst) { defaultFly(dst); }
                    };
    
                    // --- different 性质: 1 个 class
                    class ModelC: public Airplane
                    {
                    public:
                        virtual void fly(const Airport& dst);
                    };
    
                    void ModelC::fly(const Airport& dst)
                    {
                        // C 的 fly // override: 新实现 
                    }
                    
                    // ====== solution2:
                    #include <iostream>
                    class Airport { /* ... */ };
    
                    class Airplane
                    {
                    public:
                        virtual void fly(const Airport& dst) = 0;
                    };
    
                    void Airplane::fly(const Airport& dst) // pvf: define default impl
                    { 
                        /* 缺省 行为 */
                        std::cout << "pvf 可定义\n";
                    }
    
                    // --- same 性质: 2 个 class
                    class ModelA : public Airplane
                    {
                    public:
                        virtual void fly(const Airport& dst) { Airplane::fly(dst); } // override: 转调 Base::pvf
                    };
    
                    class ModelB : public Airplane
                    {
                    public:
                        virtual void fly(const Airport& dst) { Airplane::fly(dst); }
                    };
    
                    // --- different 性质: 1 个 class
                    class ModelC : public Airplane
                    {
                    public:
                        virtual void fly(const Airport& dst);
                    };
    
                    void ModelC::fly(const Airport& dst)
                    {
                        // C 的 fly // override: 新实现
                    }
    
                    int main()
                    {
                        Airplane* pb = new ModelB;
                        Airport a;
                        pb->fly(a);
                    }
        3   non-vf
    

    4 考虑 vf 之外 的 选择

        0   概述
    
            游戏软件 中 `人物  健康值计算`
            
            mem func 声明为 `impure virtual` => 暗示应该有 `缺省实现`
            
            class A
            {
            public:
                virtual int healthValue() const; // dereved class 可 override
            };
    
        1   `NVI` 手法 实现 `Template Method`
              |
              |
            non-virtual interface
            
            `NVI` ( func ) `wrap 访问性更低` 的 `vf`  
             |                          |         |
             |                          |         |
            public          private/protected    做实际工作 
    
            (1) 优点
    
                wrapper/nvi 可使在 `vf 调用 前/后`
                
                    [1] 设定适当场景
                        lock a mutex / log entry / 验证 class 约束条件
                        
                    [2] 清理场景
                        unlock a mutex / 验证 class 约束条件
    
            class A
            {
            public:
                int nvi() const
                {
                    /* 设定适当场景 */
                    
                    int ret = vf();
                    
                    /* 清理场景 */
                    
                    return ret;
                }
            private:
                virtual int vf() const 
                {
                    /* default impl */
                }
            };
        
        2   用 `fp` ( function pointer ) 实现 `Strategy` 模式
        
            `non-mem function pointer 作 mem data
                        |
                        |/
                    para 为 class 的 const 引用
    
            (1) `Strategy 模式`
                
                [1] pf (pointer to function) mem
                
                [2] ctor: receive & store 传入的 pf (策略) 到 pf mem
                
                [3] non-vf 用 pf mem 调 func(策略): *this 作 arg
                
                    class A; // 前向声明
                    int defaultPF(const A&);
    
                    class A
                    {
                    public:
                        // [1] `函数指针 类型别名`
                        typedef int (*PF)(const A&);
                        
                        // [3] ctor: receive & store 传入的 pf (策略) 到 pf mem
                        explicit A(PF pf_ = defaultPf)
                            : pf(pf_) {}
                            
                        // [4] non-vf 用 pf mem 调 func(策略): *this 作 arg
                        int nvf() const
                        {
                            return pf(*this);
                        }
                    private:
                        PF pf; // [2] pf (pointer to function) mem
                    };
    
                    class A1: public A
                    {
                    public:
                        explicit A1(PF pf = defaultPf)
                            : A(pf) { /* ... */ }
    
                    };
    
                    int PF1(const A&);
                    int PF2(const A&);
    
                    A1 person1(PF1);
                    A1 person2(PF2);
    
            (2) `相对于 A 内 vf 的 优点`
    
                [1] `不同 A object` 可拥有 `不同 策略函数`
    
                [2] `运行期 可改变 策略函数`
    
            (3) 缺点
                
                `class 封装性 降低`
    
        3   泛化
                    
                                                std::bind(&B::f3, b, _1)
                                                    |\
                                                    |   _1: 调用 &B::f3 时, 以 b 作 对象
                                                    |
                                                    |
            [1] `std::function 对象` 可持有 `任何 可调用对象`
                    
                只要 `其 签名式 ( signature )` 兼容于 `需求端`
                                                |
                                                |
                                                |/
                                            可调用对象 的 函数调用运算符 returnType `可 隐式转换为 signature 的 returnType`
                        
            [2] 与 2 相比 
            
                实现上( 仅 1 点 )
                
                    普通 `函数指针 类型别名` 
                            |
                            |   换为
                            |/
                        策略 `std::function 类型` 别名
                            typedef std::function<int (const A&)> PF;       
                    
                class A; // 前向声明
                int defaultPF(const A&);
    
                class A
                {
                public:
                    // [1] 策略 std::function 类型 `别名` 
                    typedef std::function<int (const A&)> PF;
                    
                    // [3] 
                    explicit A(PF pf_ = defaultPF)
                        : pf(pf_) {}
                    
                    / [4]
                    int nvf() const { return pf(*this); }
                private:
                    PF pf; // [2] 
                };
    
                // 1) function
                short f1(const A&);
    
                // 2) function object
                struct F2
                {
                    int operator()(const A&) const { return 1; }
                };
    
                // 3) mem func
                class B
                {
                public:
                    float f3(const A&) const; // mem func
                };
    
                class A1: public A // 同2
                {
                    /* .. */
                };
    
                // --- client
                A1 person1(f1);
                A1 person2(F2() );
    
                B b;
                A1 person3( std::bind(&B::f3, b, _1)  );
    
        4   `委托` 给 `另一 继承体系` 的 `vf`
    
            `经典 Strategy 模式`
                
                与 3 相比 
                    
                    [1] 策略 `std::function 类型` 别名` 
                                |
                                |   换为 
                                |/
                            `策略 函数对象` 
                                            含 vf  
                                             |\
                                             |  调  => `多态 即 多策略`
                                             |
                    [2] 模板类 Ctor 参数: `策略函数对象 指针` 
                
                
                class A; // 前向声明
    
                class PF                                       // [1]
                {
                public:
                    virtual int vf(const A& c) const 
                        { /* ... */ }
                };
                
                PF defaultPF; 
    
                class A
                {
                public:
                    explicit A(PF* pf_ = &defaultPF)            // [3]
                        : pf(pf_) {}
                        
                    int nvi() const { return pf->vf(*this); }   // [4]
                private:
                    PF* pf;                                     // [2]
                };
    

    5 绝不 redefine 继承而来non-virtual func: 设计上 矛盾

        class Base
        {
        public:
            void nvf();
        };
    
        class Derived: public Base
        {
        public:
            void nvf(); // hide 了 Base::nvf
        };
    
        Derived d;
    
        Base* pb = &d;
        Derived* pd = &d;
    
        pb->nvf(); // 调 Base::nvf
        pd->nvf(); // 调 Derived::nvf
    

    6 绝不 redefine 继承而来 的 vf 的 默认参数值

        1   
            ——————————————————————————————————
            [1] ptr/ ref 调 vf       动态绑定
            ——————————————————————————————————
            [2] object   调 vf   静态绑定
            ——————————————————————————————————
            [3] 缺省参数值           静态绑定        
            ——————————————————————————————————
            
                            取决于 `ptr/ref 所指 object` 的 `运行期 type`
                              |\
                              | 是 Base::vf 还是 Derived::vf 
                              |
            (1) `动态绑定 调 vf` 
                
                    vf `才` 从 base class 继承 `缺省参数`
                                                |
                                                |   是 静态绑定
                                                |
                                                |   用的是 Base::vf 还是 Derived::vf 中的 缺省参数 
                                                |/
                                            取决于 ptr / ref 的 type    
    
            (2) `override` vf `默认参数值` 的 `问题`
    
                —————————————————————————————————————————————————————————————————
                Base ptr 
                    —————————————————————————————————————————————————————————————
                    [1] 指向 Derived object
    
                    [2] 调 vf 
                        Derived::vf / Base::vf 默认参数值 不同
                    —————————————————————————————————————————————————————————————       
                    => `override` vf `默认参数值`
    
                    => `vf code 用 Derived 内那份, 但 默认参数值 用 Base 内那份`
                            
                            即, `Base 和 Derived 的 vf 声明式 各出一半力`
    
                                B* pr = new D;  // pr 静态类型为 B*
                                pr->vf(B::Color color = Green);  // D::vf(B::Color color = Red )
                —————————————————————————————————————————————————————————————————
                class B
                {
                public:
                    enum Color {Red, Green};
                    virtual void vf(Color color = Red) const = 0;
                };
    
                class D: public B
                {
                public:
                    virtual void vf(Color color = Green) const;
                };
    
                B* ps;          // ps 静态类型为 B*
                B* pr = new D;  // pr 静态类型为 B*
                ps = pr;        // ps 动态类型 变为 D*
                pr->vf();       // D::vf(B::Red)
    
        2   `若 遵守本规则`, `又想提供 缺省参数值` 给 Base 和 Derived 用户 
                
                [1] Base
                
                    1] `NVI: non-vf 指定 缺省参数` 
                                |
                                |/
                            绝不应该被 override 
                                
                                => 缺省值 总是 Base 中 版本 
                        
                    2]  调 `private pvf 负责 真正工作`
                    
                [2] Derived 
                    
                    impure vf override Base::pvf 
                    
                [3] Base ptr/ref
                    
                    1]  指向 Derived 对象 
                    
                    2]  调 non-vf ( 继承而来的 )
                    
                class B
                {
                public:
                    enum Color {Red, Green};
                    
                    // 1    NVF/non-vf 
                    void nonVf(Color color = Red) const  { doVf(color); }
                private:
                    virtual void doVf(Color color) const = 0; // 2  pure vf
                };
    
                class D: public Color
                {
                private:
                    virtual void doVf(Color color) const;     // 3  impure vf
                };
    

    7 用 composition 建模 has-a ( 有一个 ) / is-implemented-in-terms-of ( 据某物实现出 )

        1   `Composition 2 层含义`                                 class A{
                    |                                               private:
                    |/                                                  std::string name;
                是 `类型 间 关系: 类型1 对象 内含 类型2 对象`           B b;    class B { /* ... */ };
                                                                    };
                `composition` 发生于 
                    
                    `应用域 / 实现域 object 间`,
                        
                        表现出 `has-a / is-implemented-in-terms-of` 关系
                
                        
                            ——————————————————————————————————————————————————————————————
                            软件中 处理 2个领域             |
                            ——————————————————————————————————————————————————————————————
                            应用域: 所塑造的世界 中 的事物   |   人 / 汽车
                            ——————————————————————————————————————————————————————————————
                            实现域: 实现细节               |   buffer / mutex / rbtree
                            ——————————————————————————————————————————————————————————————
    
        2   应用: 用 std::list 实现 set
    
            需求: 需 template, 造出 一组 class 表现 `不重复对象 组成的 set`
    
            (1) 方法 1: 用 std::set 
            
                1) `空间 比 速度 重要 时 -> std::set 不合理`
                
                2) 速度 比 空间 重要 时 -> std::set 合理
    
            (2) 方法 2: public 继承 std::list
    
                template<typename T>
                class Set: public std::list<T>{...};
    
                问题
                    Set 与 std::list 用 is-a 关系 不合适
                        list 内 元素 可重复
                        
                        Set  内 元素 不可重复
                                        
            (3) 方法 3: Set 与 std::list 用 Composition 关系
    
                Set is-implemented-in-terms-of std::list
                
                    熟悉 STL, 则 很容易实现
                    
                template<typename T>
                class Set
                {
                private:
                    std::list<T> rep; // 用来 表述 Set 的 data           
                public:
                    bool is_member(const T& item) const;
                    void insert(const T& item);
                    void remove(const T& item);
                    std::size_t size() const;
                };
    
                template<typename T>
                bool Set<T>::is_member(const T& item) const
                {
                    // != 为 true => find -> is member
                    return std::find( rep.begin(), rep.end(), item) != rep.end();
                }
    
                template<typename T>
                void Set<T>::insert(const T& item)
                {
                    if( ! is_member(item) )
                        rep.push_back(item);
                }
    
                template<typename T>
                void Set<T>::remove(const T& item)
                {
                    typename std::list<T>::iterator iter
                        = std::find(rep.begin(), rep.end(), item);
                    
                    if(it != rep.end() )
                        rep.erase(iter);
                }
    
                template<typename T>
                std::size_t Set<T>::size() const
                {
                    return rep.size();
                }
    

    8 慎用 private 继承

        1   `private 继承` 的 `行为 & 意义`
    
            (1) 行为
    
                private 继承 下
    
                    `compiler 不会` 自动 `将 derived class 对象 转换为 base class 对象`
    
                    class Person { ... };
                    class Student: private Person{ ... };
                    void eat(const Person&);
                    void study(const Student&);
                    Student s;
                    eat(s); // error 
    
            (2) 意义
                
                只在 `软件实现层面 有意义`, 在 `软件设计层面` 没有意义
                    
                    [1] is-implemented-in-terms-of ( 据 某物 实现出 )`
                                                         |
                                                         |/
                                                        Base
                                                        
                    [2] 只有 `implement 部分 被继承, interface 部分 应略去`
    
        2   `private vs. Composition`
    
                意义都是 is-implemented-in-terms-of
    
                (1) 两者 怎么选 ?
    
                    尽可能 用 Composition
                        
                        `必要时` 才用 private 继承
                `           |
                            |   `何时才必要 ?`
                            |/
    
                        3 种情形
    
                            2 个 class (A 和 B) `不存在 is-a 关系` 
                                
                                而是 is-implemented-in-terms-of 关系 时
                            
                                    —————————————————————————————————————————————
                                    [1] A 需 `访问`     B 的 `protected 成员` 
                                    —————————————————————————————————————————————
                                    [2] A 需 `override` B 的 vf
                                    —————————————————————————————————————————————
                                    [3] `empty base 最优化`
                                    —————————————————————————————————————————————
                            
        3   is-implemented-in-terms-of 的 3 种实现
    
            需求
    
                需 `实现类 (定时器 Timer)`
    
                    `可按 任何频率 滴答, 每次滴答 调某 vf`
    
                        让 `目标类` 可以 override `实现类` 的 vf
                                            |
                                            |   目的
                                            |/
                                        访问 `目标类` 的 data 
                                            
            [1] private 继承
    
                public 继承 不合适
                
                    Widget isn't a  Timer
    
                class Timer
                {
                public:
                    explicit Timer(int tickFreq);
                    virtual void onTick() const; // 定时器 每滴答 1 次, 该函数 被 自动调用 1 次
                };
            
                class Widget: private Timer
                {
                private: 
                    virtual void onTick() const; // 访问 Widget 的 data
                };
                
            [2] `( private 区 ) Composition + public 继承`
                
                1] `成员类` public 继承 `实现类`  
                      |                     |
                      |                     |
                      |/                    |/
                    WidgetTimer         Timer
                        |
                        |/
                        放 private 区
                            
                    =>  `目标类` definition 必须 可见 `实现类` definition
                            |                     |
                            |                     |
                            |/                    |/
                         Widget             #include "实现类 定义 头文件"
                                    
                            =>  目标类  `依赖` 实现类 
            
                2] 据 `成员类` 实现 override `实现类` 的 vf`
    
    
                ——————————————————————————————————————————————————————————————————————————
                [2] 与 [1] 相比 
                    ——————————————————————————————————————————————————————————————————————
                    若想 从 目标类 `进一步派生` 
                        
                        又想 `阻止` 派生出的类 `override 成员类型 的 vf`
    
                            只能用 [2], 不能用 [1]
                ——————————————————————————————————————————————————————————————————————————
                                原因
                                    1]  private 继承 ( [1] ) => `阻止了 目标类 进一步派生` 
                                ——————————————————————————————————————————————————————————
                                    2]  ( private 区 ) Composition + public 继承 ( [2] )
                                
                                        =>  `派生出的类` 无法取用 `成员类型` 
                                                            
                                            => 无法 `override 成员类型 的 vf`
                ——————————————————————————————————————————————————————————————————————————
                
                // 1    widget.h
                class Widget
                {
                private:
                    class WidgetTimer: public Timer
                    {
                    public:
                        virtual void onTick() const; 
                    };
                    WidgetTimer timer; 
                };
    
            [3] `成员类型` 变 `成员(类型)指针`
                
                `成员类` 
                    
                    1] 本身 `移出` 
                    
                    2] 替换为 `其 指针`
                    
                            `目标类` 只需带 `成员指针 相应类型` 的 declaration
                                |                           |
                                |/                          |/
                            Widget                      WidgetTimer
                ——————————————————————————————————————————————————————————————————————              
                [3] 与 [2] 相比 
                    ——————————————————————————————————————————————————————————————————
                    1] 优势   |   目标类 `编译依赖 降低` 
                    ——————————————————————————————————————————————————————————————————
                    2] 代价   |   目标类 `无法 override 成员(类型)指针 相应类型` 的 vf  => 只是不符合 需求 中的 override
                ——————————————————————————————————————————————————————————————————————
                
                // 1    widgetTimerDecl.h
                class WidgetTimer;
                
                // 2    widget.h
                #include "widgetTimerDecl.h"
                    
                class Widget
                {
                private:
                    WidgetTimer* ptimer; 
                };
                
                // 3    widgetTimer.h
                class WidgetTimer: public Timer
                {
                public:
                    virtual void onTick() const; 
                };
    
        4   empty base 最优化
    
            (1) `empty base`
    
                无
                    non-static 成员变量
                    vf
                    virtual base class
    
                往往含
                    static 成员变量
                    non-virtual func
                    typedef
                    enum
    
                ———————————————————————————————————————————————————————
                C++ 规定
                
                    `empty class` 
                        ———————————————————————————————————————————————
                        [1] `独立 对象` 都 `必须有 非0 大小`
                            大多 compiler 做法:
                                Empty class 插 一块足够放 int 的 空间
                        ———————————————————————————————————————————————
                        [2] 作 成员对象 
                            不占空间 
                ———————————————————————————————————————————————————————
                
                // sizeof(Empty) > 0
                class Empty {}; 
    
                // sizeof(HoldsAnInt) > sizeof(int)
                class HoldsAnInt
                {
                private:
                    int x;
                    Empty e;
                };
    
            (2) `EBO / empty base optimization: private 继承 Empty class`
    
                `优势: 不增加 Derived class 大小`
                
                    [1] EBO 一般只在 单继承 下 可行
    
                    [2] STL 中 empty base, 通常内含 typedef
                
                        unary_function / binary_function
                        
                // sizeof(Empty) > 0
                class Empty {}; 
    
                // sizeof(HoldsAnInt) == sizeof(int)  
                class HoldsAnInt: private Empty
                {
                private:
                    int x;
                };      
    

    9 慎用 多重继承

    相关文章

      网友评论

          本文标题:Effective C++ 6: Inheritance & O

          本文链接:https://www.haomeiwen.com/subject/vlqymltx.html