boolan/C++面向?qū)ο蟾呒?jí)編程 part3

C++面向?qū)ο蟾呒?jí)編程 part3

@(boolan C++)[C++]


概述

面向?qū)ο蟮娜N關(guān)系

  1. composition 組合
  2. delegation 委托
  3. inheritance 繼承

組合與繼承

1. composition 組合 has a

template <class T> {
class queue {
...
protected:
    deque<T> c;

public:
    bool empyt(){ return c.empty()} 
    size_type size() {return c.size();}
    reference front() { return c.front();}
    reference back() {return c.back();}
    void push(const value_type& x) {c.push_back(x);}
    void pop()(c.pop_front();)
}

composition 是has a 的關(guān)系漆际。

composition的關(guān)系表示法:

1509872201654.png

Adapter模式

Adapter模式: 新的類(lèi)類(lèi)型組合包含已有的類(lèi)型對(duì)象却紧,新的類(lèi)型的功能完全由已有的類(lèi)型實(shí)現(xiàn)衡奥,新的類(lèi)型是已有類(lèi)型的功能的簡(jiǎn)化(類(lèi)似 adapter的功能)曲尸。

2.composition 關(guān)系下的構(gòu)造和析構(gòu)

內(nèi)存結(jié)構(gòu)

1509872239077.png

構(gòu)造和析構(gòu)順序

構(gòu)造順序由內(nèi)而外,析構(gòu)順序由外而內(nèi)。

  1. Container首先調(diào)用Component的default構(gòu)造函數(shù),后調(diào)用自己的構(gòu)造函數(shù)俊马。
    圖中紅色部分為編譯器行為
1509872269289.png
  1. Container首先調(diào)用自己的析構(gòu)函數(shù)肩杈,后調(diào)用Component的析構(gòu)函數(shù)柴我。
1509872282635.png

注意??:
構(gòu)造函數(shù)的默認(rèn)行為,編譯器默認(rèn)在構(gòu)造函數(shù)的初始化列表中調(diào)用成員對(duì)象的default構(gòu)造函數(shù)扩然。所以在初始化列表中顯式初始化成員對(duì)象效率要高于在class body內(nèi)初始化成員函數(shù)(避免了重復(fù)初始化的動(dòng)作)艘儒。

3. Delegation/委托。 Composition by reference

delegation 即Composition by reference夫偶。
通常不講pointer界睁,僅講reference。

// file string.hpp
class stringrep;

class string {
public:
....
private:
    stringrep* rep;  // pimpl
};
// string.cpp
#include "string.hpp" 

namespace {
class stringrep {
friend class string;
int count;
char* rep;
};
}

Delegation的關(guān)系表示法

1509872298319.png

delegation 雖然能夠訪(fǎng)問(wèn)某對(duì)象索守,但其成員對(duì)象是指向某對(duì)象的指針晕窑。指針成員指向的對(duì)象的創(chuàng)建和析構(gòu)都不一定由我控制抑片。

delegation中指針成員的生命周期和其所指對(duì)象的生命周期不一致卵佛。compositon中生命周期一致。

pImpl模式/ (Handle/Body)

p for pointer敞斋。

  1. pImpl將實(shí)現(xiàn)的聲明分離截汪,提供了靈活性。這種靈活性來(lái)源于delegation中指針成員生命周期與其指向?qū)ο蟮牟灰恢隆?/strong>

string的引用計(jì)數(shù)和copy on write

1509872311553.png

引用計(jì)數(shù):string中采用引用計(jì)數(shù)的方式在內(nèi)容相同對(duì)象間共享數(shù)據(jù)植捎。
copy on write:共享數(shù)據(jù)的對(duì)象間如果有人要改寫(xiě)自己的數(shù)據(jù)衙解,則copy共享的數(shù)據(jù)到新分配的內(nèi)存(目的是不破壞共享數(shù)據(jù))。

copy on write 應(yīng)用:string 對(duì)象間拷貝不會(huì)創(chuàng)建新的內(nèi)存焰枢,因?yàn)橛幸糜?jì)數(shù)機(jī)制蚓峦,僅在copy之后要改寫(xiě)對(duì)象才會(huì)創(chuàng)建新內(nèi)存(copy on write)舌剂。

4. Inheritance/ 繼承. Is - a

繼承,委托,組合都是面向?qū)ο蟆?/p>

struct _List_node_base{
    _List_node_base* _M_next;
    _List_node_base* _M_prev;
}

template<typename _Tp>
struct _List_node :public _List_node_base
{
    _Tp _M_data;
}

繼承的表示方法

1509872324297.png

T表示 Template class

public繼承

  1. public繼承 is-a關(guān)系。
  2. 繼承的價(jià)值在于與虛函數(shù)搭配暑椰。

派生類(lèi)成員對(duì)基類(lèi)成員的訪(fǎng)問(wèn)

  1. 基類(lèi)的private成員霍转,只有基類(lèi)和基類(lèi)的友元可以訪(fǎng)問(wèn)。
  2. 基類(lèi)的public一汽,protected成員避消,派生列表中使用的訪(fǎng)問(wèn)標(biāo)號(hào)決定該成員在派生類(lèi)中的訪(fǎng)問(wèn)級(jí)別

派生列表中的訪(fǎng)問(wèn)標(biāo)號(hào)

訪(fǎng)問(wèn)標(biāo)號(hào)僅影響基類(lèi)的public,potected成員在派生類(lèi)中的訪(fǎng)問(wèn)級(jí)別召夹。

  1. public繼承:基類(lèi)成員在派生類(lèi)中的訪(fǎng)問(wèn)級(jí)別保持不變岩喷。
  2. prtoceted繼承: 基類(lèi)的public,protected成員在派生類(lèi)中為protected成員监憎。
  3. private繼承:基類(lèi)的public纱意,protected成員在派生類(lèi)中為private成員。

::無(wú)論以何種方式繼承枫虏,派生類(lèi)對(duì)基類(lèi)成員的訪(fǎng)問(wèn)權(quán)限一致妇穴,繼承類(lèi)型僅影響派生類(lèi)用戶(hù)對(duì)基類(lèi)成員的訪(fǎng)問(wèn)級(jí)別。::

Inheritance關(guān)系下的構(gòu)造和析構(gòu)

內(nèi)存模型

1509872337816.png

構(gòu)造和析構(gòu)順序

構(gòu)造由內(nèi)而外隶债, 析構(gòu)由外而內(nèi)腾它。類(lèi)似于compositon的順序。

  1. Derived 的構(gòu)造函數(shù)死讹,先調(diào)用base的default構(gòu)造函數(shù)瞒滴,后調(diào)用自己的構(gòu)造函數(shù)。base的default構(gòu)造函數(shù)在derived的構(gòu)造初始化列表中被默認(rèn)調(diào)用
    Derived::Dervied(…): Base() {};

  2. Derived的析構(gòu)函數(shù)赞警,先執(zhí)行自己的析構(gòu)函數(shù)妓忍,后調(diào)用base的析構(gòu)函數(shù)。
    Derived::~Derived(…) {… ~Base()};

base的析構(gòu)函數(shù)必須是virtual

如果多態(tài)基類(lèi)的析構(gòu)函數(shù)是non-virtual的愧旦,會(huì)造成“局部對(duì)象銷(xiāo)毀”世剖,僅銷(xiāo)毀了基類(lèi)的對(duì)象。


虛函數(shù)與多態(tài)

1. derived class 繼承了 base class 的哪些東西笤虫?

  1. 內(nèi)存數(shù)據(jù)
  2. 函數(shù)的調(diào)用權(quán)

derived class 繼承了base class 的函數(shù)調(diào)用權(quán)旁瘫,所以 derived class 可以調(diào)用base class的函數(shù)。

2. Inheritance with virtual function

注意??:
virutal函數(shù)的設(shè)計(jì)取決于derived class 是否想要重新定義(override/ 覆蓋)base class的已有定義琼蚯。這里要區(qū)分重載(overload)和覆蓋(override)酬凳。

virtual function

class Shape {
public:
    virutal void draw() const = 0;  // pure virtual
    virtual void error(const std::string& msg);  // impure virtual
    int objectID() const;  // non-virtual
  1. non-virtual : 不希望derived class 重新定義(override / 覆蓋)它(base class function member)。
  2. virtual: 希望derived class重新定義它遭庶,且它已有默認(rèn)定義宁仔。
  3. pure virtual:希望derived class一定要重新定義它,且它沒(méi)有默認(rèn)定義峦睡。

理解???♂?:

  1. 虛函數(shù)的聲明在base class中指定翎苫, 控制derived class對(duì)接口的繼承能力权埠。
  2. 虛函數(shù)使derived class繼承了base class 接口的同時(shí),讓dervied class具有進(jìn)化該接口行為的能力煎谍。

注意??:

  1. 不能創(chuàng)建具有純虛函數(shù)類(lèi)型的對(duì)象弊知。
  2. 繼承于純虛類(lèi)的dervied class 中具有純虛類(lèi)對(duì)象。

template method

class CDocument {
public:
    virutal Serialize(){};
    OnFileOpen() {  // template method
        ...
        Serialize();
    }
}

class CMyDocument : public CDocument {
    virtual Serialize() {....}
}

....

int main () {
    CMyDocument doc;
    doc.OnFileOpen();
}

OnFileOpen就是template method粱快;

template method:

template method的做法將已實(shí)現(xiàn)base類(lèi)型的部分功能秩彤,延緩實(shí)現(xiàn),將其交由derived class 實(shí)現(xiàn)事哭。
將Application Framework框架和Application實(shí)現(xiàn)分離漫雷。

理解

  1. template method即 ,在其實(shí)現(xiàn)中調(diào)用base class virtual function的base class non-virtual function 鳍咱。
  2. 好處:
    derived class 可以復(fù)用base class 中non-virtual function實(shí)現(xiàn)中通用的框架/流程/接口降盹,但針對(duì)不同derived class object的調(diào)用 non-virtual function 的行為略有差異(差異在non-virtual function中調(diào)用virtual function)。

virtual function調(diào)用過(guò)程

注意下圖中this指針的作用谤辜。

1509872370689.png

3. Inheritance + Composition 關(guān)系下的構(gòu)造和析構(gòu)

內(nèi)存模型/UML關(guān)系

1509872400702.png

構(gòu)造由內(nèi)而外蓄坏,析構(gòu)由外而內(nèi)

  1. Derived 的構(gòu)造函數(shù)首先調(diào)用base的default 構(gòu)造函數(shù)
    然后調(diào)用Component的default構(gòu)造函數(shù)丑念,
    最后調(diào)用自己的構(gòu)造函數(shù)涡戳。
    Derived::Derived(...) : Base(),Component() {...};

  2. Derived 首先調(diào)用自己的析構(gòu)函數(shù),
    然后調(diào)用Component的析構(gòu)函數(shù)脯倚,
    最后調(diào)用base的析構(gòu)函數(shù)
    Derived::~Derived(){... ~Componet(),~Base()};


委托+繼承設(shè)計(jì)

設(shè)計(jì)思想:用composition(組合)/delegation(委托)/inheritance(繼承)三個(gè)工具渔彰,去設(shè)計(jì)解決現(xiàn)實(shí)問(wèn)題的方法。

理解 1:委托應(yīng)用于設(shè)計(jì)的靈活性在于對(duì)象創(chuàng)建的靈活性推正,delegation class a對(duì)象可以通過(guò)指針的方式間接擁有某對(duì)象恍涂,該被擁有的對(duì)象創(chuàng)建方式可以很動(dòng)態(tài)。

理解 2: 委托+繼承強(qiáng)化了委托的應(yīng)用植榕,鑒于base指針可以指向derived class對(duì)象再沧。

0. Obeserver

class Subject {
    int m_value;
    vector<Observer*> m_views;
public:
    void attach(Observer* obs) {
        m_views.push_back(obs);
    }
    void set_value(int value) {
        m_value = value;
        notify();
    }
    void notify() {
        for(int i = 0; i < m_views.size(); ++i)
            m_views[i]->update(this, m_value);
    }
}


class Observer {
public:
    virtual void update(Subject* sub, int value) = 0;
}

UML關(guān)系圖

1509872417801.png

1. 類(lèi)似文件系統(tǒng)的問(wèn)題解決

文件系統(tǒng)問(wèn)題?

如何設(shè)計(jì)目錄的數(shù)據(jù)結(jié)構(gòu)尊残?目錄中既有文件類(lèi)型炒瘸,又包含目錄類(lèi)型。

用composite設(shè)計(jì)模式/ delegation + inheritance 解決問(wèn)題

1509872430936.png
  1. composite解決的問(wèn)題夜郁?用一種結(jié)構(gòu)能夠同時(shí)保存多種不同類(lèi)型的數(shù)據(jù)什燕。
  2. base類(lèi)指針數(shù)組粘勒,解決上述問(wèn)題竞端,注意必須是指針數(shù)組,因?yàn)橹羔樀拇笮」潭ā?/li>

example code

class Primitive : public Component {
public:
    Primitive(int val): Component(val){}
};

class Component {
    int value;
public:
    Component(int val) {value = val;}
    virutal void add(Component*) {}
};

class Composite: public Component {
    vector<Component*>c;
public:
    Composite(int val):Component(val) {}

    void add(Componet* elem) {
        c.push_back(elem);
    }
}

2. Prototype

UML

1509872444226.png
  1. 靜態(tài)成員的表示方法庙睡,在成員的名稱(chēng)下面添加下劃線(xiàn)
  2. 數(shù)據(jù)成員的表示方法事富,成員名稱(chēng)在前技俐,類(lèi)型在后。

Prototype要解決的問(wèn)題

  1. 在base類(lèi)種如何創(chuàng)建未來(lái)才會(huì)設(shè)計(jì)的類(lèi)型對(duì)象统台。在不知道對(duì)象類(lèi)型的前提下創(chuàng)建對(duì)象雕擂。
  2. 主要發(fā)生在框架設(shè)計(jì)中,框架設(shè)計(jì)者不知道未來(lái)使用者的類(lèi)型贱勃。

注意??:

  1. prototype中井赌,是在dervied類(lèi)自己創(chuàng)建對(duì)象,不是使用者創(chuàng)建dervied對(duì)象贵扰,所以dervied類(lèi)中包含一個(gè)static derived類(lèi)對(duì)象仇穗。
  2. derived類(lèi)自己創(chuàng)建對(duì)象并注冊(cè)到base類(lèi)中。
  3. prototype中戚绕,base類(lèi)中創(chuàng)建derived類(lèi)對(duì)象纹坐,而不是base類(lèi)/dervied類(lèi)對(duì)象中的base對(duì)象

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市舞丛,隨后出現(xiàn)的幾起案子耘子,更是在濱河造成了極大的恐慌,老刑警劉巖球切,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谷誓,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡吨凑,警方通過(guò)查閱死者的電腦和手機(jī)片林,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)怀骤,“玉大人费封,你說(shuō)我怎么就攤上這事〗祝” “怎么了弓摘?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)痕届。 經(jīng)常有香客問(wèn)我韧献,道長(zhǎng),這世上最難降的妖魔是什么研叫? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任锤窑,我火速辦了婚禮,結(jié)果婚禮上嚷炉,老公的妹妹穿的比我還像新娘渊啰。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布绘证。 她就那樣靜靜地躺著隧膏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嚷那。 梳的紋絲不亂的頭發(fā)上胞枕,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音魏宽,去河邊找鬼腐泻。 笑死,一個(gè)胖子當(dāng)著我的面吹牛队询,可吹牛的內(nèi)容都是我干的贫悄。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼娘摔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼窄坦!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起凳寺,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鸭津,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后肠缨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體逆趋,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年晒奕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了闻书。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脑慧,死狀恐怖魄眉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情闷袒,我是刑警寧澤坑律,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站囊骤,受9級(jí)特大地震影響晃择,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜也物,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一宫屠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧滑蚯,春花似錦浪蹂、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至创葡,卻和暖如春浙踢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背灿渴。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工洛波, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人骚露。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓蹬挤,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親棘幸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子焰扳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容