C&C++ 虛函數(shù)實(shí)現(xiàn)的基本原理

本文根據(jù)眾多互聯(lián)網(wǎng)博客內(nèi)容整理后形成,引用內(nèi)容的版權(quán)歸原始作者所有,僅限于學(xué)習(xí)研究使用,不得用于任何商業(yè)用途踩叭。

1. 概述

簡(jiǎn)單地說(shuō)替饿,每一個(gè)含有虛函數(shù)(無(wú)論是其本身的翅睛,還是繼承而來(lái)的)的類(lèi)都至少有一個(gè)與之對(duì)應(yīng)的虛函數(shù)表力喷,其中存放著該類(lèi)所有的虛函數(shù)對(duì)應(yīng)的函數(shù)指針慷妙。例:

image.png

其中:

  • B的虛函數(shù)表中存放著B(niǎo)::foo和B::bar兩個(gè)函數(shù)指針。

  • D的虛函數(shù)表中存放的既有繼承自B的虛函數(shù)B::foo芹枷,又有重寫(xiě)(override)了基類(lèi)虛函數(shù)B::bar的D::bar衅疙,還有新增的虛函數(shù)D::quz。

提示:為了描述方便鸳慈,本文在探討對(duì)象內(nèi)存布局時(shí)饱溢,將忽略?xún)?nèi)存對(duì)齊對(duì)布局的影響。

2. 虛函數(shù)表構(gòu)造過(guò)程

從編譯器的角度來(lái)說(shuō)走芋,B的虛函數(shù)表很好構(gòu)造绩郎,D的虛函數(shù)表構(gòu)造過(guò)程相對(duì)復(fù)雜。下面給出了構(gòu)造D的虛函數(shù)表的一種方式(僅供參考):

image.png

提示:該過(guò)程是由編譯器完成的翁逞,因此也可以說(shuō):虛函數(shù)替換過(guò)程發(fā)生在編譯時(shí)肋杖。

3. 虛函數(shù)調(diào)用過(guò)程

以下面的程序?yàn)槔?/p>

image.png

編譯器只知道pb是B*類(lèi)型的指針,并不知道它指向的具體對(duì)象類(lèi)型 :pb可能指向的是B的對(duì)象挖函,也可能指向的是D的對(duì)象状植。

但對(duì)于“pb->bar()”,編譯時(shí)能夠確定的是:此處operator->的另一個(gè)參數(shù)是B::bar(因?yàn)閜b是B*類(lèi)型的,編譯器認(rèn)為bar是B::bar)浅萧,而B(niǎo)::bar和D::bar在各自虛函數(shù)表中的偏移位置是相等的逐沙。

無(wú)論pb指向哪種類(lèi)型的對(duì)象哲思,只要能夠確定被調(diào)函數(shù)在虛函數(shù)中的偏移值洼畅,待運(yùn)行時(shí),能夠確定具體類(lèi)型棚赔,并能找到相應(yīng)vptr了帝簇,就能找出真正應(yīng)該調(diào)用的函數(shù)。

B::bar是一個(gè)虛函數(shù)指針靠益, 它的ptr部分內(nèi)容為9丧肴,它在B的虛函數(shù)表中的偏移值為8(8+1=9)。

當(dāng)程序執(zhí)行到“pb->bar()”時(shí)胧后,已經(jīng)能夠判斷pb指向的具體類(lèi)型了:

  • 如果pb指向B的對(duì)象芋浮,可以獲取到B對(duì)象的vptr,加上偏移值8((char*)vptr + 8)壳快,可以找到B::bar纸巷。

  • 如果pb指向D的對(duì)象,可以獲取到D對(duì)象的vptr眶痰,加上偏移值8((char*)vptr + 8) 瘤旨,可以找到D::bar。

  • 如果pb指向其它類(lèi)型對(duì)象...同理...

4. 多重繼承

當(dāng)一個(gè)類(lèi)繼承多個(gè)類(lèi)竖伯,且多個(gè)基類(lèi)都有虛函數(shù)時(shí)存哲,子類(lèi)對(duì)象中將包含多個(gè)虛函數(shù)表的指針(即多個(gè)vptr),例:

image.png

其中:D自身的虛函數(shù)與B基類(lèi)共用了同一個(gè)虛函數(shù)表七婴,因此也稱(chēng)B為D的主基類(lèi)(primary base class)祟偷。

虛函數(shù)替換過(guò)程與前面描述類(lèi)似,只是多了一個(gè)虛函數(shù)表打厘,多了一次拷貝和替換的過(guò)程修肠。

虛函數(shù)的調(diào)用過(guò)程,與前面描述基本類(lèi)似婚惫,區(qū)別在于基類(lèi)指針指向的位置可能不是派生類(lèi)對(duì)象的起始位置氛赐,以如下面的程序?yàn)槔?/p>

[圖片上傳失敗...(image-4d80cf-1581389064147)]

5. 菱形繼承

本文不討論菱形繼承的情形,個(gè)人覺(jué)得:菱形繼承的復(fù)雜度遠(yuǎn)大于它的使用價(jià)值先舷,這也是C++讓人又愛(ài)又恨的原因之一艰管。

如果想要深入研究,可以參考:Itanium C++ ABI蒋川。

參考文檔
C/C++雜記:虛函數(shù)的實(shí)現(xiàn)的基本原理

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末牲芋,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缸浦,老刑警劉巖夕冲,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異裂逐,居然都是意外死亡歹鱼,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)卜高,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)弥姻,“玉大人,你說(shuō)我怎么就攤上這事掺涛⊥ザ兀” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵薪缆,是天一觀的道長(zhǎng)秧廉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)拣帽,這世上最難降的妖魔是什么疼电? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮诞外,結(jié)果婚禮上澜沟,老公的妹妹穿的比我還像新娘。我一直安慰自己峡谊,他們只是感情好茫虽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著既们,像睡著了一般濒析。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上啥纸,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天号杏,我揣著相機(jī)與錄音,去河邊找鬼斯棒。 笑死盾致,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的荣暮。 我是一名探鬼主播庭惜,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼穗酥!你這毒婦竟也來(lái)了护赊?” 一聲冷哼從身側(cè)響起惠遏,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎骏啰,沒(méi)想到半個(gè)月后节吮,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡判耕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年透绩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祈秕。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡渺贤,死狀恐怖雏胃,靈堂內(nèi)的尸體忽然破棺而出请毛,到底是詐尸還是另有隱情,我是刑警寧澤瞭亮,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布方仿,位于F島的核電站,受9級(jí)特大地震影響统翩,放射性物質(zhì)發(fā)生泄漏仙蚜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一厂汗、第九天 我趴在偏房一處隱蔽的房頂上張望委粉。 院中可真熱鬧,春花似錦弄屡、人聲如沸昼激。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)栗涂。三九已至,卻和暖如春祈争,著一層夾襖步出監(jiān)牢的瞬間斤程,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工菩混, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留忿墅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓沮峡,卻偏偏與公主長(zhǎng)得像疚脐,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子帖烘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

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

  • 技術(shù)交流QQ群:1027579432亮曹,歡迎你的加入橄杨! 1.概述 每一個(gè)含有虛函數(shù)(無(wú)論是其本身就含有的,還是從基類(lèi)...
    CurryCoder閱讀 262評(píng)論 0 2
  • 1照卦、前言 簡(jiǎn)單地說(shuō)式矫,每一個(gè)含有虛函數(shù)(無(wú)論是其本身的,還是繼承而來(lái)的)的類(lèi)都至少有一個(gè)與之對(duì)應(yīng)的虛函數(shù)表役耕,其中存放...
    王王王王王景閱讀 570評(píng)論 0 0
  • 原創(chuàng):神秘編程神秘編程今天 問(wèn)題拋出:為什么要使用多態(tài)采转?如果子類(lèi)定義了與父類(lèi)中原型相同的函數(shù)會(huì)發(fā)生什么? 多態(tài):同...
    編程小兔崽閱讀 549評(píng)論 0 0
  • 剛加完班現(xiàn)在開(kāi)始寫(xiě)日志瞬痘,時(shí)間過(guò)得真快呀轉(zhuǎn)眼孩子開(kāi)學(xué)一個(gè)多星期了故慈,在這段時(shí)間里孩子的變化真大,她不在是上幼兒園里的那...
    雅琳媽媽閱讀 218評(píng)論 0 0
  • 弦月幽幽框全,竹笛輕奏察绷。是怎樣的一場(chǎng)離別匆匆,將相思婉約在唐詩(shī)宋詞中津辩,攜一縷清風(fēng)拆撼,尋一季幽香,用歲月做箋喘沿,譜一曲相思盡...
    Ann安墨染閱讀 383評(píng)論 2 10