美文网首页
Inheritance & Composition & Dele

Inheritance & Composition & Dele

作者: my_passion | 来源:发表于2020-06-14 15:32 被阅读0次
    Inheritance 继承
    Composition 组合/复合
    Delegation 委托
    
    `Object Oriented Programming: OOP`
    `Object Oriented Design: OOD`
    

    1 Inheritance

    1. 内存角度
    
    14.jpg
    2. Inheritance 下的 构造 和 析构: 
    与Composition 思路相同
    

    (1) 构造 由内而外

    Derived::Derived(...) : Base() { ... }
    

    (2) 析构 由外而内

    Derived::~Derived(...) : { ... ~Base() }
    
    `Base 的 dtor 必须是 virtual, 否则 可能出现 undefined behavior`
    
    => class 现在或将来 可能是 父类, 则将其 dtor 设为 virtual
    
    3. 带虚函数 的 继承: 继承 + 虚函数 才有威力
    

    (1) non-vf: 不希望 子类 override (redefine) 自己

    `本类 己经实现, 且 不让子类再做动作`
    

    (2) vf: 希望 子类 override ( redefine ) 自己, 且 自己有 默认定义

    => 非纯虚
    `本类 可以实现, 且 允许子类 有自己的新实现`
    

    (3) pvf: 希望 子类 override 自己, 且 自己 没 默认定义

    => 纯虚
    `本类 没法实现, 但 想提供统一接口, 让子类去实现`
    
    class Shape
    {
    public:
        int generateId();
        virtual void error(const std::String& msg);
        virtual void draw() const = 0;
    };
    

    4. 数据/函数 继承

    数据 继承: 内存角度

    函数继承: 继承的是 函数的 调用权

    , 子类 可以调用 父类的函数
    

    2 Composition

    1. deque
    
    template <class T, class Sequence = deque<T> >
    class queue
    {
    ...
    protected:
        Sequence c;  //底层容器
    public:
        // 以下 完全用 c 的 函数完成
        bool empty() const { return c.empty(); }
        size_type size() const { return c.size(); }
        reference front() const { return c.front(); }
        reference back() const { return c.back(); }
    
        // deque 是两端可进出,queue 是末端进前端出
        void push(const value_type& x) { c.push_back(x); }
        void pop() { c.pop_front(); }
    };
    
    母语: /`dek/
    
    黑色菱形: 其中有东西
    
    类 queue 拥有 1个 东西 c, c 的类型 是 deque<T>
    

    Composition: 类 A 拥有(1/n 个) 类B, 2个类的关系为 has-a

    A (queue) 借用 B( deque ) 已有功能 来实现 自己的功能 — 设计模式 Adapter

    内存角度 看 Composition

    10.jpg 11.jpg
    2. Composition 下的 构造 和 析构
    

    (1) 内存角度

    12.jpg

    (2) 构造 由内而外:

    这样 基础才稳定
    Container ctor 先调 Component ctor, 
    然后才 执行自己
    
    若 Container ctor 函数名 和 函数体 之间 
    `不 explicitly 调 Component` 的 ctor, 
    则 编译器 隐含自动加 default ctor 
    
    Container::Container(...): Component() { ... }
    

    (3) 析构 由外而内:

    像一层层 剥洋葱一样
    Container 的 dtor 先执行自己, 然后 调用Component 的 dtor
    
    若 Container dtor 最后 `不 expliciy 调Component` 的 dtor
    则 编译器 隐含自动调 default dtor
    
    Container::~Container(...): { ... ~Component() }
    

    3 Delegation: Composition by reference

    左边 拥有一个 右边的指针, 即 左边 用 指针 指向 右边

     => 这个 拥有 不是 立即拥有, 
    而是 在需要右边的时候 才 通过右边的指针 调用右边, 
    把任务 委托 给 右边  
    => 左 右 不同步: 左右生存期不同, 左 需要 右时, 才创建右
    

    委托 没有 Composition by reference 表达得清晰

    `学术界 不讲 by pointer, 只讲 by reference, 
    即使是用 pointer 在传`
    
    // file String.hpp
    class StringRep;
    class String
    {
    public:
        String();
        String(const char* s);
        String(const string& s);
        String& operator = (const String& s);
    private:
        StringRep* rep; //---pimp
    };
    
    //file String.cpp
    #include "String.hpp"
    namespace
    {
    
    class StringRep
    {
        StringRep(const char* s);
        ~StringRep();
        int count;
        char* rep;
    }
    
    }
    
    String::String()
    { ... }
    

    编译防火墙:
    左边 对外 interface 不变, 右边 怎么变动都行, 都不影响 client

    13.jpg

    4 Inheritance with virtual -> 多态

    1. Template Method

    本类/framework 先实现 自己能实现的 func, 自己 不能实现的 func 设为 vf, 留给 子类/application 去实现

    windows 下 通过菜单 逐级寻找, 最后 打开文件 的 framework:
    framework 中 无法完成 打开文件, 交给 具体 application
    
    `Template Method` 的 一个 `example:` 
    `函数 OnFileOpen 的 implement 方法`,
    
    该 example 也是 `MFC(Microsoft Foundation Classes)`
    这套卖钱的产品 中 `大量使用 的 手法`
    
    TemplateMethod.jpg 15.jpg this_1.jpg

    myDoc.OnFileOpen() 引发 静+动 态绑定

    (1) 用 Derived obj 调 Base non-vf / vf => &obj 作 arg 传给 implicit para this => 均 静态绑定

    myDoc.OnFileOpen(): &myDoc 作 arg 传给 CDocument::OnFileOpen() 的 implicit para this ( CDocument* )

    =>
    

    形实结合 CDocument* this = &myDoc

    &myDoc/CMyDoc* upcast 为 CDocument*

    (2) Base non-vf 又用 多态 ptr 调 vf => 动 态绑定

    CDocument::OnFileOpen() 又 用 多态 ptr this (this: Base ptr 指向 derived_obj myDoc)vf / this->Serialize()

    this_2.jpg
    #include<iostream>
    //------ FrameWork
    class CDocument
    {
    public:
        void OnFileOpen();
    
        //这里 Serialize() 为 纯虚函数 或 空函数 都可以
        virtual void Serialize() = 0;
        //virtual void Serialize(){ }
    };
    
    void CDocument::OnFileOpen()
    {
        //如下 每个 std::cout 表示一个 实际动作
        std::cout << "dialog..." << std::endl;
        std::cout << "check file status..." << std::endl;
        std::cout << "Open file..." << std::endl;
    
        //(3) this->Serialize()
        // 父类 non-virtual func 中 用 pointer this 调 
        //   父类 pure virtual func =>
        // this -> 运行时 obj/myDoc 的 vptr -> vtbl 
        // -> 子类中 override 的 vf 
        Serialize();
    
        std::cout << "close file..." << std::endl;
        std::cout << "update all views..." << std::endl;
    
    }
    //------ App
    class CMyDoc : public CDocument
    {
    public:
        virtual void Serialize()
        {
            //(4) 子类 override 父类 pure vf
            // reason: 只有 application 本身 才知道 如何读取自己的文件
            std::cout << "CMyDoc::Serialize()..." << std::endl;
        }
    };
    int main()
    {
        //(1) create subclass obj
        CMyDoc myDoc;
    
        //(2) 通过 子类 obj 调 继承自 父类 的 non-virtual func
        // => 
        // 1) 静态绑定
        // 2) &obj_subclas 作 arg 传给 父类 该 func 的 para this:
        // CDocument::OnFileOpen(&myDoc)
        // => 形实结合 CDocument* this = &myDoc
        // => this/CDocument* downcast 为 &myDoc/CMyDoc*
        myDoc.OnFileOpen();
    }
    
    image.png image.png image.png
    myDoc.OnFileOpen(): 
    通过 obj 调 非虚函数 => 静态绑定
    
    image.png
    this->Serialize(): 
    通过 父类 pointer 调 子类对象 的 虚函数 => 动态绑定
    
    image.png

    2. 动/静 态绑定 本质区别

    (1) `静态绑定 ( 通过 obj 调用 vf/non-vf ):`
    

    编译时, 把 相应 statement 编译成 func addr, 运行/调用时 直接 call 固定的 func addr

    image.png
    (2) `动态绑定 ( 必须 通过 ptr/ ref 调 vf ):` 
    

    运行时, 才能 通过 &obj -> vptr -> vtbl -> call 的 vf ptr

    image.png

    5 Inheritance + Composition 下的 构造 和 析构

    16.jpg
    #include<iostream>
    using namespace std;
    
    class Base
    {
    public:
        Base() { cout << "Base..." << endl; }
    };
    
    class Component
    {
    public:
        Component() { cout << "Component..." << endl; }
    };
    
    class Derived : public Base
    {
    public:
        Derived() { cout << "Derived..." << endl; }
    private:
        Component component;
    };
    
    int main()
    {
        Derived derived;
    }
    
    //---print
    Base...
    Component...
    Derived...
    

    6 Inheritance + Delegation: 功能强大

    Observer 模式

    UI ( User Interface )

    程序设计
    
    文件:1份存储, 多种表现
    
    多种表现:
    1) powerPoint: 4个窗口 看同一格式的 该文件 — 相同 Observer
    2) Graph: 不同 角度 ( 曲线 / 散点图) 看 该文件 — 不同 Observer
    

    左边 ( 放 data ) 拥有 多个 右边的 pointer ( 观察 左边 data ) => 把 View 功能 delegate 给 右边 各具体 Observer

    client 可以开 多个 Observer 
    
    左 `pimp` 右
    
    17.jpg

    相关文章

      网友评论

          本文标题:Inheritance & Composition & Dele

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