深度探索C++對象模型-第五章

說明:

? <u>不是很清楚的點(diǎn)</u>,用下劃線欧啤。

? 解答店印,用斜體;

? 重點(diǎn),用粗體加粗兰珍;

第五章 構(gòu)造掠河、析構(gòu)唠摹、拷貝 語意學(xué)

5.1 純虛函數(shù)

  • 擁有純虛函數(shù)的類勾拉,為抽象類,不可能擁有實(shí)例(不可能創(chuàng)造出一個(gè)對象)。

    但若抽象類中有數(shù)據(jù)成員惩激,則需要一個(gè)顯式的構(gòu)造函數(shù)去初始化它酒请。

  • 不要把析構(gòu)函數(shù)聲明為 pure(純)布朦。

  • 不要給一個(gè)虛函數(shù)后面加 const是趴。

5.2 “無繼承”情況下的對象構(gòu)造

當(dāng)一個(gè)class導(dǎo)入一個(gè)虛函數(shù)時(shí),會發(fā)生下列事情:

  1. 每一個(gè)class object多負(fù)擔(dān)一個(gè)vptr没佑;
  2. 自己定義的構(gòu)造函數(shù)被附加了一些代碼,實(shí)現(xiàn)vptr的初始化远剩;
  3. 合成拷貝構(gòu)造函數(shù)腹纳、賦值構(gòu)造函數(shù),因?yàn)関ptr不能用默認(rèn)的bitwise方式復(fù)制了;

5.3 繼承體系下的對象構(gòu)造

在繼承下象缀,編譯器會擴(kuò)充每一個(gè)constructor,擴(kuò)充程度視繼承體系而定爷速。

constructor的調(diào)用伴隨了哪些步驟央星?

  • 初始化列表(member initialization list)的data members初始化操作會被放進(jìn)constructor的函數(shù)本身,并以members的聲明順序?yàn)轫樞?/strong>惫东。(如*this->x = 0;)

  • 如果有一個(gè)member并沒有在初始化列表中莉给,但它在一個(gè)default constructor,那么該default constructor 必須被調(diào)用(手動)。

  • 在那之前禁谦,如果class object有virtual table pointer(s)胁黑,它(們)必須被設(shè)定初始值,指定適當(dāng)?shù)膙irtual table(s)州泊。

  • 在那之前,所有上一層的base class constructors 必須被調(diào)用漂洋,以base class 的聲明順序?yàn)轫樞颍ㄅc初始化列表的順序沒有關(guān)聯(lián))遥皂。

    1. 如果base class 被列于初始化列表中,那么任何明確指定參數(shù)都應(yīng)該傳遞過去刽漂。

    2. 如果base class 沒有列于初始化列表演训,那么調(diào)用default constructor。

    3. 如果base class 是多重繼承下的第二或后面的base class 贝咙,那么this指針必須有所調(diào)整样悟。

  • <u>在那之前,所有 virtual base class constructors 必須被調(diào)用庭猩,從左到右窟她,從最深到最淺。</u>

    1. 如果class 被列于初始化列表中蔼水,那么如果有任何明確指定的參數(shù)震糖,都應(yīng)該傳遞過去,若沒有列于初始化列表中趴腋,則調(diào)用default constructor吊说。
    2. 此外,class中的每一個(gè)virtual base class subobject的偏移量必須在執(zhí)行期可存取优炬。
    3. 如果class object 是最底層的class颁井,某constructors可能被調(diào)用;某些用以支持這個(gè)行為的機(jī)制必須被放進(jìn)來蠢护。

【注】在那之前雅宾,是指在用戶代碼執(zhí)行前。

其中的虛擬繼承

為了防止重復(fù)對virtual base class調(diào)用構(gòu)造函數(shù)糊余,規(guī)定:只有在繼承體系最深層的object才可以對virtual父類進(jìn)行調(diào)用構(gòu)造初始化秀又。

其中的vptr語意學(xué)

vptr在constructor何時(shí)被初始化?

base class constructors調(diào)用操作之后贬芥,但是在程序員供應(yīng)的碼或是初始化列表中所列的members初始化操作之前吐辙。

5.4 對象復(fù)制語意學(xué)

在復(fù)制操作時(shí),需要一個(gè)面對自我拷貝的過濾過程:

if( this == &rhs) return *this;

當(dāng)設(shè)計(jì)一個(gè)class蘸劈,并以一個(gè)class object 指定另一個(gè)class object時(shí)昏苏,有三種選擇:

  1. 什么都不做,實(shí)施默認(rèn)行為。

  2. 提供一個(gè)explicit copy assignment operator贤惯。

  3. 明確拒絕一個(gè)class object指定給另一個(gè)class object洼专。

一個(gè)class對于默認(rèn)的copy assignment operator,在以下情況下不會表現(xiàn)出 bitwise copy語意:

  1. 當(dāng)一個(gè)class的 base class 有一個(gè)copy assignment operator時(shí)孵构,

  2. 當(dāng)一個(gè)class 的 member object屁商,而其 class 有一個(gè) copy assignment operator 時(shí),

  3. 當(dāng)一個(gè)class 聲明了任何 virtual functions 時(shí)颈墅,

  4. 當(dāng)class繼承一個(gè) virtual base class 時(shí)蜡镶。但盡可能不要允許一個(gè)virtual base class的拷貝操作,也盡量不要在其中聲明數(shù)據(jù)恤筛。

構(gòu)造這樣的一個(gè)繼承體系:

class Base {
    public: virtual ~Base() {}
    virtual void show() { cout << "Base" << endl; }
};

class Derived : public Base {
    public: void show() { cout << "Derived" << endl; }
};

子類Derived類重寫了基類Base中的show方法官还。 編寫下面的測試代碼:

Base b; 
Derived d;

b.show(); 
d.show();

結(jié)果是:

Base

Derived

Base的對象調(diào)用了Base的方法,而Derived的對象調(diào)用了Derived的方法毒坛。因?yàn)橹苯佑脤ο髞碚{(diào)用成員函數(shù)時(shí)不會開啟多態(tài)機(jī)制望伦,故編譯器直接根據(jù)b和d各自的類型就可以確定調(diào)用哪個(gè)show函數(shù)了,也就是在這兩句調(diào)用中煎殷,編譯器為它們每一個(gè)都確定了一個(gè)唯一的入口地址屯伞。這實(shí)際上類似于一個(gè)重載多態(tài),雖然這兩個(gè)show函數(shù)擁有不同的作用域蝌数。 那這樣呢: Base b; Derived d; b.show(); b = d; b.show(); 現(xiàn)在愕掏,一個(gè)Base的對象被賦值為子類Derived的對象。

那這樣呢:

Base b; 
Derived d;

b.show(); 
b = d; 
b.show();

現(xiàn)在顶伞,一個(gè)Base的對象被賦值為子類Derived的對象饵撑。

結(jié)果是:

Base

Base

對于熟悉Java的人而言,這不可理解唆貌。但實(shí)際上滑潘,C++不是Java,它更像C锨咙∮锫保“b = d”的意思,并不是Java中的“讓一個(gè)指向Base類的引用指向它的子類對象”酪刀,而是“把Base類的子類對象中的Base子對象分割出來粹舵,賦值給b”。所以骂倘,只要b的類型始終是Base眼滤,那么b.show()調(diào)用的永遠(yuǎn)都是Base類中的show函數(shù);換句話說历涝,編譯器總是把Base中的那個(gè)show函數(shù)的入口地址作為b.show()的入口地址诅需。這根本就沒用上多態(tài)漾唉。

單繼承下的重寫多態(tài)

那我們再這樣:

Base b; 
Derived d;
Base *p = &b;

p->show();
p = &d;
p->show();

這時(shí),結(jié)果就對了:

Base

Derived

p是一個(gè)指向基類對象的指針堰塌,第一次它指向一個(gè)Base對象赵刑,p->show()調(diào)用了Base類的show函數(shù);而第二次它指向了一個(gè)Derived對象场刑,p->show()調(diào)用了Derived類的show函數(shù)般此。

總結(jié):也就是說,只有是指針或者引用才是真正的多態(tài)牵现,將子對象賦給父類對象其實(shí)類型向上轉(zhuǎn)型

個(gè)人覺得C++容易弄混淆的地方(持續(xù)更新):

1.const和指針的修飾問題

const char * a; //一個(gè)指針a指向const char

char const *a; //這兩個(gè)是a指向的內(nèi)容是常量恤煞,不能改變

char * const a; //首先a 是指針然后還是const

const (char*) a; //這兩個(gè)是a指針本身是常量,指針本身不能改變

其實(shí)施籍,可以看出如果const修飾的char(也就是類型本身或者是 *variable對指針的解引用)就是指針指向的內(nèi)容是常量,反之就是修飾指針本身的概漱。那我們可以總結(jié)一個(gè)識別方法就是:看const 兩邊(當(dāng)然有的只有一邊)的類型是類型(指針指向的內(nèi)容)就是類型變量本身是常量(如const char * a和char const a 的const兩邊是char丑慎,a)。

當(dāng)然兩者都是常量就是:const char * const a;第一個(gè)const是類型常量瓤摧,第二個(gè)才是指針常量竿裂。同樣給出 const char &a ;const char *a;在傳遞參數(shù)時(shí)使用。

2.數(shù)組和指針的組合問題

char * a[M]; 這是指針數(shù)組照弥,就是每一個(gè)元素是指針的數(shù)組腻异,每個(gè)元素都要初始化。a[M]一看就是數(shù)組这揣,這個(gè)數(shù)組每一個(gè)元素是char *悔常,所以可以將char *擴(kuò)展為一維數(shù)組然后a[M]就是二維數(shù)組了。其實(shí)就是M個(gè)指針给赞。

char (a)[N]; 這是一個(gè)指針机打,這個(gè)指針指向N個(gè)char元素,即指向數(shù)組的指針片迅,其實(shí)就是一個(gè)指針残邀。把(a)看著一個(gè)變量,這個(gè)變量是指向N個(gè)元素的指針柑蛇,所以只是一個(gè)一維數(shù)組芥挣。把char (*a)[N]看成是char b[N]就可以了。

3.C++變量的初始化

對于內(nèi)置類型局部變量不進(jìn)行初始化耻台,但是分配地址空免,全局變量會進(jìn)行默認(rèn)初始化。對于類類型局部變量(沒有顯式初始化)會進(jìn)行默認(rèn)初始化(有默認(rèn)構(gòu)造函數(shù)粘我,否則報(bào)錯(cuò))鼓蜒,但其內(nèi)部的內(nèi)置數(shù)據(jù)成員不會進(jìn)行初始化(如果在默認(rèn)構(gòu)造函數(shù)沒有進(jìn)行初始化)痹换。數(shù)組也是同樣。

參考文章

《深度探索C++對象模型(Inside The C++ Object Model )》學(xué)習(xí)筆記:https://dsqiu.iteye.com/blog/1669614

c++都弹,為什么要引入虛擬繼承 :https://www.cnblogs.com/mylinux/p/4725833.html

RTTI娇豫、虛函數(shù)和虛基類的實(shí)現(xiàn)方式、開銷分析及使用指導(dǎo):http://baiy.cn/doc/cpp/inside_rtti.htm

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末畅厢,一起剝皮案震驚了整個(gè)濱河市冯痢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌框杜,老刑警劉巖浦楣,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異咪辱,居然都是意外死亡振劳,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門油狂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來历恐,“玉大人,你說我怎么就攤上這事专筷∪踉簦” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵磷蛹,是天一觀的道長吮旅。 經(jīng)常有香客問我,道長味咳,這世上最難降的妖魔是什么庇勃? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮莺葫,結(jié)果婚禮上匪凉,老公的妹妹穿的比我還像新娘。我一直安慰自己捺檬,他們只是感情好再层,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著堡纬,像睡著了一般聂受。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烤镐,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天蛋济,我揣著相機(jī)與錄音,去河邊找鬼炮叶。 笑死碗旅,一個(gè)胖子當(dāng)著我的面吹牛渡处,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播祟辟,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼医瘫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了旧困?” 一聲冷哼從身側(cè)響起醇份,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吼具,沒想到半個(gè)月后僚纷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拗盒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年怖竭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陡蝇。...
    茶點(diǎn)故事閱讀 40,133評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡侵状,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出毅整,到底是詐尸還是另有隱情,我是刑警寧澤绽左,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布悼嫉,位于F島的核電站,受9級特大地震影響拼窥,放射性物質(zhì)發(fā)生泄漏戏蔑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一鲁纠、第九天 我趴在偏房一處隱蔽的房頂上張望总棵。 院中可真熱鬧,春花似錦改含、人聲如沸情龄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽骤视。三九已至,卻和暖如春鹃觉,著一層夾襖步出監(jiān)牢的瞬間专酗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工盗扇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留祷肯,地道東北人沉填。 一個(gè)月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像佑笋,于是被迫代替她去往敵國和親翼闹。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評論 2 355

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

  • 從前我很鄙視微商, 現(xiàn)在颠锉,我自己就是一名微商法牲。 自從淘寶解決了萬千人民的就業(yè)問題之后,微信的發(fā)展也逐漸催生出了一個(gè)...
    一只大瑞閱讀 1,937評論 0 0
  • Everyone may encounter all kinds of intersections, someti...
    大林dalin閱讀 527評論 0 50
  • 核心內(nèi)容部分 一琼掠、具有以下特質(zhì)有助于提高成功的心理預(yù)期1拒垃、認(rèn)同努力與結(jié)果的協(xié)變。2瓷蛙、相信對于結(jié)果的控制源自于自身悼瓮,...
    昆明家庭教育聯(lián)盟閱讀 903評論 0 1
  • 今天是星期日,我和媽媽打掃衛(wèi)生艰猬,我們先掃地横堡,后有又拖地。我自己收拾了我的學(xué)習(xí)桌冠桃,又把我們曬干的收拾衣服收拾起來命贴。屋...
    董子璐閱讀 208評論 0 0
  • test2 test2 API列表 API名稱 認(rèn)證方式 描述 getUserInfo APP ge...
    tommyhxh閱讀 1,492評論 0 0