Inheritance & Composition & Dele

2020-06-14  本文已影响0人  my_passion
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
上一篇下一篇

猜你喜欢

热点阅读