技術(shù)交流QQ群:1027579432,歡迎你的加入!
1.概述
- 每一個(gè)含有虛函數(shù)(無論是其本身就含有的,還是從基類繼承過來的)的類都至少有一個(gè)與之對(duì)應(yīng)的虛函數(shù)表趣斤,其中存放著該類所有的虛函數(shù)對(duì)應(yīng)的函數(shù)指針俩块。如下圖所示
:
虛函數(shù)表.png
其中:- B的虛函數(shù)表中存放著B::foo和B::bar兩個(gè)函數(shù)指針
- D的虛函數(shù)表中存放的既有繼承自B的虛函數(shù)B::foo黎休,又有重寫了基類虛函數(shù)B::bar的D::bar,還有新增的虛函數(shù)D::quz玉凯。
2.虛函數(shù)表的構(gòu)造過程
-
從編譯器的角度來說势腮,B的虛函數(shù)表很好構(gòu)造,D的虛函數(shù)表構(gòu)造過程相對(duì)復(fù)雜漫仆,下面給出了構(gòu)造D的虛函數(shù)表的一種方式捎拯,該過程是由編譯器完成的,即虛函數(shù)替換過程發(fā)生在編譯時(shí):
D的虛函數(shù)表構(gòu)造過程.png
3.虛函數(shù)的調(diào)用過程
-
以下面的程序?yàn)槔?/p>
虛函數(shù)的調(diào)用過程.png - 編譯器只知道pb是B*類型的指針盲厌,并不知道它指向的具體對(duì)象類型署照,pb可能指向的是B的對(duì)象,也有可能指向的是D的對(duì)象吗浩。但對(duì)于pb->bar()建芙,編譯時(shí)能確定的是:此處->的另一個(gè)參數(shù)是B::bar(因?yàn)閜b是B*類型的,編譯器認(rèn)為bar是B::bar)懂扼,而B::bar和D::bar在各自虛函數(shù)表中的偏移位置是相等的禁荸。無論pb指向哪種類型的對(duì)象右蒲,只要能夠確定被調(diào)函數(shù)在虛函數(shù)表的偏移值,等到運(yùn)行時(shí)能夠確定具體類型赶熟,并能找到相應(yīng)的vptr瑰妄,這樣就能找出真正應(yīng)該調(diào)用的函數(shù)。由于虛函數(shù)指針中的ptr部分為虛函數(shù)表中的偏移值(以字節(jié)為單位)+1映砖,所以B::bar是一個(gè)虛函數(shù)指針间坐,它的ptr部分內(nèi)容是9,它在B的虛函數(shù)表中的偏移值為8邑退。當(dāng)程序執(zhí)行到pb->bar()時(shí)眶诈,已經(jīng)能夠判斷pb指向的具體類型了:
- a.如果pb指向B的對(duì)象,可以獲取到B對(duì)象的vptr瓜饥,加上偏移值8(char(*)vptr + 8)逝撬,可以找到B::bar
- b.如果pb指向的是D的對(duì)象,可以獲取D的對(duì)象vptr乓土,加上偏移值8(char(*)vptr + 8)宪潮,可以找到D::bar
3.多重繼承
-
當(dāng)一個(gè)類繼承多個(gè)類,且多個(gè)基類都有虛函數(shù)時(shí)趣苏,子類對(duì)象中將包含多個(gè)虛函數(shù)表中的指針(即多個(gè)vptr)狡相,如下所示:
多重繼承.png -
其中:D的自身虛函數(shù)與B基類共用了同一個(gè)虛函數(shù)表,因此稱B為D的主基類食磕。虛函數(shù)替換過程與前面描述類似尽棕,只是多了一個(gè)虛函數(shù)表,多了一次拷貝和替換的過程彬伦。虛函數(shù)的調(diào)用過程滔悉,與前面基本類似,區(qū)別在于基類指針指向的位置可能不是派生類對(duì)象的起始位置单绑,如下面的程序所示:
多重繼承的函數(shù)調(diào)用.png