【GeekBand】C++面向?qū)ο蟾呒?jí)編程-第三周筆記

課堂大綱:

1.組合與繼承
1.1 Composition 復(fù)合
1.2 Delegation 委托
1.3 Inheritance 繼承
2.虛函數(shù)與多態(tài)
2.1虛函數(shù)


正文

1.組合與繼承

1.1Composition 復(fù)合

復(fù)合表示has-a,表示一個(gè)類(lèi)里含有另一個(gè)類(lèi)的對(duì)象(非指針及引用)蛛倦。
例如

    template<class T>
    class queue
    {
        ...
    protected:
        deque<T> c;   //底層容器
    };

其中c是該類(lèi)的一個(gè)成員歌懒,是c這個(gè)對(duì)象及其成員變量是占據(jù)queue內(nèi)存的。
UML表示方法是:

2016-05-26_082626.png

黑色實(shí)心菱形從queue類(lèi)指向deque類(lèi)溯壶,一個(gè)簡(jiǎn)單的記憶方法是:菱形是實(shí)心的及皂,表示這個(gè)queue是真的有這個(gè)deque的實(shí)體,然后這個(gè)菱形指向了deque類(lèi)且改,表示這個(gè)菱形表示deque验烧。
Composition關(guān)系下的構(gòu)造和析構(gòu)
構(gòu)造:
構(gòu)造是由內(nèi)而外,就像打包裹又跛,從里往外碍拆。先構(gòu)造components的對(duì)象再構(gòu)造container,這是編譯器自動(dòng)完成的慨蓝。

Container::Container(...):Component(){...};

析構(gòu):
析構(gòu)是由外而內(nèi)感混,就像拆包裹,從外往里礼烈。先析構(gòu)Container再析構(gòu)components的弧满,這也是編譯器自動(dòng)完成的。

Container::~Container(){~Component();}

1.2 Delegation委托

委托表示composition by reference此熬,表示一個(gè)類(lèi)里含有另一個(gè)類(lèi)的指針或者引用對(duì)象庭呜。
例如:

class String
{
private:
    StringRep* rep; //pimml
};

string.JPG

黑色空心菱形從String類(lèi)指向StringRep類(lèi),一個(gè)簡(jiǎn)單的記憶方法是:菱形是空心的犀忱,表示這個(gè)String是只有這個(gè)StringRep的指針對(duì)象或者引用疟赊,然后這個(gè)菱形指向了StringRep類(lèi),表示這個(gè)菱形表示StringRep類(lèi)峡碉。
著名的寫(xiě)法:編譯防火墻
一個(gè)類(lèi)A只提供接口近哟,具體實(shí)現(xiàn)用另一個(gè)類(lèi)B來(lái)完成,其中A與B的 關(guān)系是委托關(guān)系鲫寄,好處是可以切換具體實(shí)現(xiàn)吉执,不影響接口。
編譯防火墻.JPG

a b c共享數(shù)據(jù)地来,如果a要改數(shù)據(jù)戳玫,那么系統(tǒng)就會(huì)復(fù)制一份專(zhuān)門(mén)給a修改,而不會(huì)影響b和c 的使用未斑。

1.3Inheritance 繼承

復(fù)合表示is-a
例如:

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

UML表示方式為:

繼承.JPG

圖中表示的方式與前面兩種略有不同咕宿,結(jié)合三角形,可以看成是有子類(lèi)指向父類(lèi),這是一個(gè)泛化的過(guò)程府阀,譬如老虎→動(dòng)物缆镣。
其中繼承方式有public、protected试浙、private三種董瞻,現(xiàn)簡(jiǎn)單介紹一下其特性。

public protected private
公共繼承 public protected 不可見(jiàn)
私有繼承 private private 不可見(jiàn)
保護(hù)繼承 protected protected 不可見(jiàn)

在上圖中:1)基類(lèi)成員對(duì)派生類(lèi)都是:共有和保護(hù)的成員是可見(jiàn)的田巴,私有的的成員是不可見(jiàn)的钠糊。
** 2)基類(lèi)成員對(duì)派生類(lèi)的對(duì)象來(lái)說(shuō):要看基類(lèi)的成員在派生類(lèi)中變成了什么類(lèi)型的成員。如:私有繼承時(shí)壹哺,基類(lèi)的共有成員和私有成員都變成了派生類(lèi)中的私有成員抄伍,因此對(duì)于派生類(lèi)中的對(duì)象來(lái)說(shuō)基類(lèi)的共有成員和私有成員就是不可見(jiàn)的。**

父類(lèi)中的數(shù)據(jù)會(huì)被子類(lèi)繼承下來(lái)管宵,但是子類(lèi)能否直接訪問(wèn)這些數(shù)據(jù)需要根據(jù)上表的特性來(lái)考慮逝慧。
當(dāng)繼承與虛函數(shù)搭配時(shí),能充分發(fā)揮出繼承的價(jià)值啄糙。關(guān)于虛函數(shù),下文會(huì)提到云稚。
繼承關(guān)系下的構(gòu)造和析構(gòu)
構(gòu)造:
繼承關(guān)系下的構(gòu)造還是由內(nèi)而外地隧饼,derived類(lèi)先構(gòu)造base類(lèi)的,再構(gòu)造自己的静陈,這是編譯器自動(dòng)完成的

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

析構(gòu):
析構(gòu)則是由外而內(nèi)地燕雁,先析構(gòu)derived的再析構(gòu)base的,這也是編譯器自動(dòng)完成

Derived::~Derived() {~Base();}

值得注意的是鲸拥,《Effective C++》條款07中有提到

當(dāng)derived class 對(duì)象經(jīng)由一個(gè)base class指針被刪除拐格,而該base class 帶有一個(gè)non-virtual 析構(gòu)函數(shù)時(shí),其結(jié)果未有定義——實(shí)際執(zhí)行時(shí)通常發(fā)生的是對(duì)象的derived成分沒(méi)被銷(xiāo)毀刑赶。
消除這個(gè)問(wèn)題的做法很簡(jiǎn)單:給base class 一個(gè)virtual析構(gòu)函數(shù)捏浊。此后刪除derive class對(duì)象就會(huì)如你想要的那般。

讀者可以簡(jiǎn)單地寫(xiě)一個(gè)類(lèi)來(lái)測(cè)試一下撞叨,這里筆者就隨便寫(xiě)一個(gè)例子來(lái)說(shuō)明這個(gè)問(wèn)題金踪。

#include<iostream>
using namespace std;

class Base
{
public:
    Base( ) { cout << "I'm Base's Ctor" << endl; }
    ~Base( ) { cout << "I'm Base's Dtor" << endl;}
};

class Derived: public Base
{
public:
    Derived( ) { cout << " I'm Derived's Ctor"<<endl; }
    ~Derived( ){cout<<"I'm Derived's Dtor"<<endl;}
};

int main()
{
    Base *base = new Derived;
    delete base;
}

運(yùn)行結(jié)果:


捕獲.JPG

可以清楚看到這就發(fā)生了上述內(nèi)存泄露的問(wèn)題了。為此
修改程序如下:

#include<iostream>
using namespace std;

class Base
{
public:
    Base( ) { cout << "I'm Base's Ctor" << endl; }
    virtual ~Base( ) { cout << "I'm Base's Dtor" << endl;}
};

class Derived: public Base
{
public:
    Derived( ) { cout << " I'm Derived's Ctor"<<endl; }
    ~Derived( ){cout<<"I'm Derived's Dtor"<<endl;}
};

int main()
{
    Base *base = new Derived;
    delete base;
}

運(yùn)行結(jié)果如下:

捕獲1.JPG

所以在父類(lèi)的析構(gòu)函數(shù)中加了virtual關(guān)鍵字后牵敷,delete父類(lèi)指針時(shí)可以還調(diào)用子類(lèi)的析構(gòu)函數(shù)胡岔,從而避免了內(nèi)存泄露。
值得提醒一下的時(shí)枷餐,《Effective C++》07條款中給的提醒是:

無(wú)端地將所有classes的析構(gòu)函數(shù)聲明為virtual靶瘸,就像從未聲明它們virtual一樣,都是錯(cuò)誤的。許多人的心得是:只有當(dāng)class內(nèi)含至少一個(gè)virtual函數(shù)才為它聲明virtual析構(gòu)函數(shù)

好了怨咪,終于進(jìn)入下一部分了屋剑。

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

2.1虛函數(shù)

首先簡(jiǎn)單介紹三個(gè)關(guān)于虛函數(shù)的名詞:
non-virtual函數(shù):非虛函數(shù),這個(gè)函數(shù)是你不希望子類(lèi)重新定義它惊暴。
virtual函數(shù):虛函數(shù)饼丘,你希望子類(lèi)重新定義,而且父類(lèi)中已經(jīng)定義過(guò)這個(gè)函數(shù)辽话。
pure virtual函數(shù): 純虛函數(shù)肄鸽,你希望子類(lèi)一定要重新定義且父類(lèi)中并無(wú)默認(rèn)定義。
例子如下:

class Shape
{
public:
    virtual void draw( ) const = 0; //純虛函數(shù)
    virtual void error( const std::string& msg);//虛函數(shù)
    int objectID( ) const;//非虛函數(shù)
    ...
};

class Rectangle: public Shape {...};
class Ellipse:public Shape{...};
```
**繼承+復(fù)合關(guān)系下的構(gòu)造和析構(gòu)**

![捕獲3.JPG](http://upload-images.jianshu.io/upload_images/2020078-f84f329c06b6ff91.JPG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
三個(gè)類(lèi)的關(guān)系如上圖所示油啤,那么我們用簡(jiǎn)單的程序測(cè)試一下:

```C++
#include<iostream>
using namespace std;
 
class Base
{
public:
  Base(){cout<<"Base ctor!"<<endl;}  
  ~Base(){cout<<"Base dtor!"<<endl;}
  int base;
};
 
class Component
{
public:
  Component(){cout<<"Component ctor!"<<endl;}  
  ~Component(){cout<<"Component dtor!"<<endl;}
  int component;
};
 
class Derived:public Base
{
public:
  Derived(){cout<<"Derived ctor!"<<endl;} 
  ~Derived(){cout<<"Derived dtor!"<<endl;}
  int derived;
  Component cpt;
};
 
int main()
{
  Derived d;
  return 0;
}
```
運(yùn)行結(jié)果是:
```
Base ctor!
Component ctor!
Derived ctor!
Derived dtor!
Component dtor!
Base dtor!
```
那么如下圖的關(guān)系呢典徘,我們?cè)傩薷囊幌鲁绦驕y(cè)試一下:
![捕獲4.JPG](http://upload-images.jianshu.io/upload_images/2020078-641806665254d409.JPG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
```C++
#include<iostream>
using namespace std;
 
 
class Component
{
public:
  Component(){cout<<"Component ctor!"<<endl;}  
  ~Component(){cout<<"Component dtor!"<<endl;}
  int component;
};
 
class Base
{
public:
  Base(){cout<<"Base ctor!"<<endl;}  
  ~Base(){cout<<"Base dtor!"<<endl;}
  int base;
  Component cpt;
};
 
class Derived:public Base
{
public:
  Derived(){cout<<"Derived ctor!"<<endl;} 
  ~Derived(){cout<<"Derived dtor!"<<endl;}
  int derived;
};
 
int main()
{
  Derived d;
  return 0;
}
```
運(yùn)行結(jié)果是:
```C++
Component ctor!
Base ctor!
Derived ctor!
Derived dtor!
Base dtor!
Component dtor!
```
和打包裹的例子是一致的,打包(構(gòu)造)的時(shí)候是先包裝最里面的益咬,然后再一層一層裝外面的逮诲。拆包(析構(gòu))都是從最外面的包裝開(kāi)始拆起,直到拆到后面發(fā)現(xiàn)盒子里只剩下這么一點(diǎn)空氣了:)

**委托+繼承**
*待續(xù)...*

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末幽告,一起剝皮案震驚了整個(gè)濱河市梅鹦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌冗锁,老刑警劉巖齐唆,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異冻河,居然都是意外死亡箍邮,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)叨叙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)锭弊,“玉大人,你說(shuō)我怎么就攤上這事擂错∥吨停” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵钮呀,是天一觀的道長(zhǎng)桃犬。 經(jīng)常有香客問(wèn)我,道長(zhǎng)行楞,這世上最難降的妖魔是什么攒暇? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮子房,結(jié)果婚禮上形用,老公的妹妹穿的比我還像新娘就轧。我一直安慰自己,他們只是感情好田度,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布妒御。 她就那樣靜靜地躺著,像睡著了一般镇饺。 火紅的嫁衣襯著肌膚如雪乎莉。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天奸笤,我揣著相機(jī)與錄音惋啃,去河邊找鬼。 笑死监右,一個(gè)胖子當(dāng)著我的面吹牛边灭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播健盒,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼绒瘦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了扣癣?” 一聲冷哼從身側(cè)響起惰帽,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎父虑,沒(méi)想到半個(gè)月后该酗,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡频轿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了烁焙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片航邢。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖骄蝇,靈堂內(nèi)的尸體忽然破棺而出膳殷,到底是詐尸還是另有隱情,我是刑警寧澤九火,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布赚窃,位于F島的核電站,受9級(jí)特大地震影響岔激,放射性物質(zhì)發(fā)生泄漏勒极。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一虑鼎、第九天 我趴在偏房一處隱蔽的房頂上張望辱匿。 院中可真熱鬧键痛,春花似錦、人聲如沸匾七。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)昨忆。三九已至丁频,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間邑贴,已是汗流浹背席里。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留痢缎,地道東北人胁勺。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像独旷,于是被迫代替她去往敵國(guó)和親署穗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

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