深度探索C++對(duì)象模型-第四章

說(shuō)明:

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

? 解答,用斜體假夺;

? 重點(diǎn)淮蜈,用粗體加粗已卷;

第四章 Function 語(yǔ)意學(xué)

4.1 Member的各種調(diào)用方式

1. Nonstatic Member Functions

實(shí)際上編譯器是將member function被內(nèi)化為nonmember的形式,經(jīng)過(guò)下面轉(zhuǎn)化步驟:

  1. 給函數(shù)添加額外參數(shù)——this侧蘸;
  2. 將對(duì)每一個(gè)nonstaitc data member的存取操作改為this指針來(lái)存取讳癌;
  3. 將member function 重寫成一個(gè)外部函數(shù)。對(duì)函數(shù)名采用mangling 處理晌坤,使之成為獨(dú)一無(wú)二的語(yǔ)匯逢艘;

2. Virtual Member Functions(虛成員函數(shù))

? ptr->f(); //f()為虛成員函數(shù)

內(nèi)部轉(zhuǎn)化為

? (*ptr->vptr[1])(ptr);

其中:

  • vptr表示編譯器產(chǎn)生的指針泡仗,指向virtual table埋虹。它被安插在每一個(gè)聲明有(或繼承自)一個(gè)或多個(gè)virtual functions 的class object 中。
  • 1 是virtual table slot的索引值娩怎,關(guān)聯(lián)到normalize()函數(shù)搔课。
  • 第二個(gè)ptr表示this指針。

3. Static Member Functions (靜態(tài)成員函數(shù))

Static Member Functions的主要特性就是它沒(méi)有this指針

次要特性:

  • 不能被聲明為const、volatile爬泥、virtual柬讨;
  • 不能夠直接存取其class中的非靜態(tài)數(shù)據(jù)成員;

Static Member Functions由于缺乏this指針袍啡,因此差不多等同于非成員函數(shù)踩官。

如果取一個(gè)static member function 的地址,獲得的是其在內(nèi)存的位置(也就是地址)境输,而不是一個(gè)指向“class member function”的指針蔗牡,如下:

&Point::count();

會(huì)得到一個(gè)數(shù)值,類型是:

unsigned int(*)();

而不是:

unsigned int(Point::*)();

4.2 Virtual Member Functions

C++中嗅剖,多態(tài)表示以“一個(gè)public base class 的指針(或reference)辩越,尋址出一個(gè)derived class object”。

為了在執(zhí)行期調(diào)用正確的虛函數(shù)信粮,在編譯時(shí)期:

  • 可以在每一個(gè)多態(tài)的class object身上增加兩個(gè)members:
  1. 一個(gè)字符串或數(shù)字黔攒,表示class的類型;
  2. 一個(gè)指針vptr强缘,指向某一個(gè)表格督惰,表格中持有程序的虛函數(shù)們的執(zhí)行期地址;
  • 每一個(gè)虛函數(shù)都被指派一個(gè)表格索引值旅掂;

那么赏胚,表格中的虛函數(shù)們地址如何被購(gòu)建起來(lái)?

在C++中辞友,虛函數(shù)們可經(jīng)由其class object被調(diào)用栅哀,可以在編譯時(shí)期獲知。此外称龙,這一組地址是固定不變的,執(zhí)行期不可能新增或替換之戳晌。由于程序執(zhí)行時(shí)鲫尊,表格的大小和內(nèi)容都不會(huì)改變,所以其建構(gòu)和存取皆可以由編譯器完全掌控沦偎。不需要執(zhí)行期的任何介入疫向。**

執(zhí)行期要做的,只是在特定的虛函數(shù)表slot中激活虛函數(shù)豪嚎。


每一個(gè)class 只會(huì)有一個(gè)virtual table搔驼,每一個(gè)table 含有對(duì)應(yīng)的class object中所有active virtual functions 函數(shù)實(shí)體地址。這些active virtual function 包括:

  1. 這個(gè)class 所定義的函數(shù)實(shí)體(包括改寫一個(gè)可能存在的base class virtual function函數(shù)實(shí)體)舌涨。
  2. 繼承自base class 的函數(shù)實(shí)體(不被derived class改寫)
  3. 一個(gè)pure_virtual_called()扔字。

繼承過(guò)程中温技,virtual table的三種可能性:

  1. 繼承base class 所聲明的virtual functions的函數(shù)實(shí)體。正確地說(shuō)舵鳞,是該函數(shù)實(shí)體的地址會(huì)被拷貝到derived class的virtual table相對(duì)應(yīng)的slot之中。
  2. 使用自己的函數(shù)實(shí)體蜓堕。這表示它自己的函數(shù)實(shí)體地址必須放在對(duì)應(yīng)的slot之中博其。
  3. 可以加入一個(gè)新的virtual function。這時(shí)候virtual table 的尺寸會(huì)增大一個(gè)slot放進(jìn)這個(gè)函數(shù)實(shí)體地址霜旧。

編譯時(shí)期設(shè)定virtual function的調(diào)用:

ptr->z();

  • 一般而言儡率,我并不知道ptr 所指對(duì)象的真正類型。然而可以經(jīng)由ptr 可以存取到該對(duì)象的virtual table儿普。
  • 雖然我不知道哪個(gè)Z()函數(shù)實(shí)體被調(diào)用,但知道每一個(gè)Z()函數(shù)地址都被放置某一個(gè)slot(如slot 4)的索引个绍。

這樣我們就可以將

ptr->z();

轉(zhuǎn)化為:

(*ptr->vptr[4])(ptr);

唯一一個(gè)在執(zhí)行期才能知道的東西是:slot4所指的到底是哪一個(gè)class object的z()函數(shù)實(shí)體浪汪。

多重繼承下的 Virtual Functions

在多重繼承中支持virtual functions,其復(fù)雜度圍繞在第二個(gè)及其后面的base class 上广恢,以及“必須在執(zhí)行期調(diào)整this 指針”這一點(diǎn)呀潭。

一般規(guī)則是,經(jīng)由指向“第二或后繼base class 的指針”來(lái)調(diào)用derived class virtual function钠署。調(diào)用操作連帶的“必要的this指針調(diào)整”操作,必須在執(zhí)行期完成舰蟆。

在多重繼承下,一個(gè)派生類內(nèi)含n-1個(gè)額外的虛函數(shù)表信卡,n表示其上一層基類的個(gè)數(shù)(因此,單一繼承將不會(huì)有額外的虛函數(shù)表)傍菇〗缗猓【若是雙重繼承,那么就會(huì)有一個(gè)與派生類共享的虛函數(shù)表

如下圖:

4-2.png

【注】

  • base1的虛函數(shù)表是主要表格咐低,base2的是次要表格袜腥;
  • 函數(shù)后面有加*,表示這不是真實(shí)的函數(shù)實(shí)例鲤屡,是需要加this指針指向真正的函數(shù)實(shí)例。

4.3 函數(shù)的效能

non-member酒来、static member或non-static member函數(shù)都被轉(zhuǎn)換為完全相同形式肪凛,所以三者效率完全相同。

4.4 指向Member Function的指針

取一個(gè)non-static data member的地址翘鸭,得到的結(jié)果是該member在class 布局中的bytes位置(再加1)远荠,所以它需要綁定于某個(gè)class object的地址上,才能夠被存取譬淳。

取一個(gè)non-static member function的地址邻梆,如果該函數(shù)是non-virtual绎秒,則得到的是內(nèi)存的真正地址,然后這個(gè)值也是不完全的,也需要綁定于某個(gè)class object的地址上蠢涝,才能夠調(diào)用函數(shù)阅懦。(所有的non-static member function都需要對(duì)象的地址,以參數(shù)this指出)

支持“指向Virtual Member Function”之指針

對(duì)于一個(gè)virtual function耳胎,其地址在編譯時(shí)期是未知的,所能知道的僅是virtual function在其相關(guān)之virtual table的索引值废登,也就是說(shuō)郁惜,對(duì)于一個(gè)virtual member function 取其地址,所能獲得的只是一個(gè)索引值兆蕉。

4.5 Inline Function

形參:

  • 傳入?yún)?shù),直接替換半醉;
  • 傳入常量劝术,連替換都省了,直接變成常量养晋;
  • 傳入函數(shù)運(yùn)行結(jié)果,則需要導(dǎo)入臨時(shí)變量逊抡,以避免重復(fù)求值;

局部變量:

一般而言冒嫡,inline函數(shù)中的每一個(gè)局部變量都必須被放在函數(shù)調(diào)用的一個(gè)封閉區(qū)段中四苇,擁有一個(gè)獨(dú)一無(wú)二的名稱。

如果一次性調(diào)用N次蟀架,就會(huì)出現(xiàn)N個(gè)臨時(shí)變量……程序的體積會(huì)暴增,如下:

minval = min( val1, val2 ) + min( foo(), foo()+1 );

因此要以分離的多個(gè)式子被調(diào)用片拍。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市苫纤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌方面,老刑警劉巖色徘,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異横腿,居然都是意外死亡斤寂,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門罗侯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)溪猿,“玉大人,你說(shuō)我怎么就攤上這事诊县。” “怎么了避除?”我有些...
    開(kāi)封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵胸嘁,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我性宏,道長(zhǎng),這世上最難降的妖魔是什么蝌借? 我笑而不...
    開(kāi)封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任指蚁,我火速辦了婚禮,結(jié)果婚禮上凝化,老公的妹妹穿的比我還像新娘。我一直安慰自己瞧哟,他們只是感情好枪向,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著陨亡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪负蠕。 梳的紋絲不亂的頭發(fā)上倦畅,一...
    開(kāi)封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音欲账,去河邊找鬼。 笑死敬惦,一個(gè)胖子當(dāng)著我的面吹牛谈山,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奏路,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼斜脂!你這毒婦竟也來(lái)了触机?” 一聲冷哼從身側(cè)響起玷或,我...
    開(kāi)封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤片任,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后位他,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鹅髓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年窿冯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了醋粟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡厦凤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出较鼓,到底是詐尸還是另有隱情,我是刑警寧澤博烂,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布漱竖,位于F島的核電站,受9級(jí)特大地震影響馍惹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜悼吱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一良狈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧薪丁,春花似錦馅精、人聲如沸努溃。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)称近。三九已至,卻和暖如春刨秆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背衡未。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留如失,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓褪贵,卻偏偏與公主長(zhǎng)得像抗俄,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子动雹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

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