一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

C 虛函數(shù)表及多態(tài)內(nèi)部原理詳解

 zeroxer2008 2022-01-13

(給CPP開(kāi)發(fā)者加星標(biāo),提升C/C++技能)

來(lái)源:CSDN -  神技圈子
https://blog.csdn.net/songguangfan/article/details/87898915

C++ 中的虛函數(shù)的作用主要是實(shí)現(xiàn)了多態(tài)的機(jī)制。關(guān)于多態(tài),簡(jiǎn)而言之就是用父類(lèi)型別的指針指向其子類(lèi)的實(shí)例,然后通過(guò)父類(lèi)的指針調(diào)用實(shí)際子類(lèi)的成員函數(shù)。這種技術(shù)可以讓父類(lèi)的指針有“多種形態(tài)”,這是一種泛型技術(shù)。

虛函數(shù)表

每個(gè)含有虛函數(shù)的類(lèi)都有一個(gè)虛函數(shù)表(Virtual Table)來(lái)實(shí)現(xiàn)的。簡(jiǎn)稱(chēng)為V-Table。C++的編譯器應(yīng)該是保證虛函數(shù)表的指針存在于對(duì)象實(shí)例中最前面的位置(這是為了保證取到虛函數(shù)表的有最高的性能——如果有多層繼承或是多重繼承的情況下)。這意味著我們通過(guò)對(duì)象實(shí)例的地址得到這張?zhí)摵瘮?shù)表,然后就可以遍歷其中函數(shù)指針,并調(diào)用相應(yīng)的函數(shù)。

1、 每一個(gè)類(lèi)都有虛函數(shù)列表。

2、 虛表可以繼承,如果子類(lèi)沒(méi)有重寫(xiě)虛函數(shù),那么子類(lèi)虛表中仍然會(huì)有該函數(shù)的地址,只不過(guò)這個(gè)地址指向的是基類(lèi)的虛函數(shù)實(shí)現(xiàn)。如果基類(lèi)3個(gè)虛函數(shù),那么基類(lèi)的虛表中就有三項(xiàng)(虛函數(shù)地址),派生類(lèi)也會(huì)有虛表,至少有三項(xiàng),如果重寫(xiě)了相應(yīng)的虛函數(shù),那么虛表中的地址就會(huì)改變,指向自身的虛函數(shù)實(shí)現(xiàn)。如果派生類(lèi)有自己的虛函數(shù),那么虛表中就會(huì)添加該項(xiàng)。

3、 派生類(lèi)的虛表中虛函數(shù)地址的排列順序和基類(lèi)的虛表中虛函數(shù)地址排列順序相同,子類(lèi)獨(dú)有的虛函數(shù)放在后面。

當(dāng)定義一個(gè)有虛函數(shù)類(lèi)的對(duì)象時(shí),對(duì)象的第一塊的內(nèi)存空間就是一個(gè)指向虛函數(shù)列表的指針。

在這舉個(gè)例子

假設(shè)我們有這樣的一個(gè)類(lèi):

由于例程的操作環(huán)境是64位系統(tǒng),所以用long*強(qiáng)轉(zhuǎn)。其中(long*)(&b)就是虛函數(shù)表地址,(long*)*(long*)(&b)就是第一個(gè)函數(shù)地址,代碼運(yùn)行結(jié)果如下:

在程序中取出對(duì)象b的地址,根據(jù)對(duì)象的布局可以得出就是虛表的地址,根據(jù)這個(gè)地址可以把虛表的第一個(gè)內(nèi)存單元的內(nèi)容取出,然后強(qiáng)制轉(zhuǎn)換成一個(gè)函數(shù)指針,利用這個(gè)函數(shù)指針來(lái)訪問(wèn)虛函數(shù)。又因?yàn)樘摫硎沁B續(xù)的,利用每次+1可以來(lái)訪問(wèn)下一個(gè)內(nèi)存單元。

如果對(duì)代碼不理解的話,可以看這幅圖就會(huì)懂了

注意:虛函數(shù)表在最后會(huì)有一個(gè)結(jié)束標(biāo)志,為1說(shuō)明還有虛表,為0表示沒(méi)有虛表了 。(編譯器不同,結(jié)束標(biāo)志可能存在差異)

下面,將分別具體說(shuō)明“無(wú)虛函數(shù)覆蓋”和“有虛函數(shù)覆蓋”時(shí)的虛函數(shù)表的情況。

(一)無(wú)虛函數(shù)覆蓋

沒(méi)有任何的繼承,虛函數(shù)表如下圖

根據(jù)示意圖,編寫(xiě)的代碼如下圖所示:

和上一個(gè)程序一樣,根據(jù)取出虛表里面的地址強(qiáng)制轉(zhuǎn)換成函數(shù)指針,同樣,利用虛表的連續(xù)性,每次指針+1調(diào)用對(duì)應(yīng)的虛函數(shù)??梢缘贸鎏摵瘮?shù)按照其聲明順序存放于虛函數(shù)表中的,子類(lèi)自己的虛函數(shù)是排在父類(lèi)虛函數(shù)之后的。運(yùn)行結(jié)果如下圖

(二)一般繼承(有虛函數(shù)覆蓋)

如果子類(lèi)中有虛函數(shù)重載了父類(lèi)的虛函數(shù),會(huì)是一個(gè)什么樣子?假設(shè),我們有下面這樣的一個(gè)繼承關(guān)系。如圖所示:

在這個(gè)類(lèi)的設(shè)計(jì)中,只覆蓋了父類(lèi)的一個(gè)函數(shù):f()。那么,對(duì)于派生類(lèi)的實(shí)例,其虛函數(shù)表會(huì)是下面的一個(gè)樣子:

從表中可以看到下面幾點(diǎn),

1)覆蓋的f()函數(shù)被放到了虛表中原來(lái)父類(lèi)虛函數(shù)的位置。

2)沒(méi)有被覆蓋的函數(shù)依舊。

這樣就會(huì)出現(xiàn)虛調(diào)用

Base *b = new Derive();

b->f();

由b所指的內(nèi)存中的虛函數(shù)表的f()的位置已經(jīng)被Derive::f()函數(shù)地址所取代,于是在實(shí)際調(diào)用發(fā)生時(shí),是Derive::f()被調(diào)用了。這就實(shí)現(xiàn)了多態(tài)。下面我們用一個(gè)示例代碼來(lái)看一下

運(yùn)行結(jié)果如下,確實(shí)如我們以上分析的那樣,由b所指的內(nèi)存中的虛函數(shù)表的f()的位置已經(jīng)被Derive::f()函數(shù)地址所取代:

(三)多重繼承(無(wú)虛函數(shù)覆蓋)

下面我們?cè)倏纯炊嘀乩^承的情況

對(duì)于子類(lèi)實(shí)例中的虛函數(shù)表,是下面這個(gè)樣子:

從圖上我們可以看到

1)每個(gè)父類(lèi)都有自己的虛表。

2) 子類(lèi)的成員函數(shù)被放到了第一個(gè)父類(lèi)的表中。(所謂的第一個(gè)父類(lèi)是按照聲明順序來(lái)判斷的)

這樣做就是為了解決不同的父類(lèi)類(lèi)型的指針指向同一個(gè)子類(lèi)實(shí)例,而能夠調(diào)用到實(shí)際的函數(shù)。

下面我們根據(jù)上圖來(lái)實(shí)現(xiàn)一下

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

在這個(gè)程序中,子類(lèi)有多個(gè)父類(lèi),因此從每個(gè)父類(lèi)都繼承了一個(gè)虛表,因此會(huì)有3個(gè)虛表,根據(jù)代碼和運(yùn)行結(jié)果會(huì)發(fā)現(xiàn),排列的順序和繼承的順序一樣,子類(lèi)自己的虛函數(shù)排在第一個(gè)虛表的后面。程序中沒(méi)有改寫(xiě)虛函數(shù) ,因此沒(méi)有覆蓋。同時(shí)主函數(shù)中應(yīng)用的是一個(gè)二重指針,利用二維數(shù)組取每個(gè)虛函數(shù)地址。

(四)多重繼承(有虛函數(shù)覆蓋)

下面我們?cè)賮?lái)看看,如果發(fā)生虛函數(shù)覆蓋的情況。

下圖中,我們?cè)谧宇?lèi)中覆蓋了父類(lèi)的f()函數(shù)。

子類(lèi)虛函數(shù)列表如圖所示

三個(gè)父類(lèi)虛函數(shù)表中的f()的位置被替換成了子類(lèi)的函數(shù)指針。這樣,我們就可以任一靜態(tài)類(lèi)型的父類(lèi)來(lái)指向子類(lèi),并調(diào)用子類(lèi)的f()了。

子類(lèi)虛函數(shù)列表訪問(wèn)代碼如下:

程序運(yùn)行結(jié)果如下所示:

本程序中,子類(lèi)重寫(xiě)了f函數(shù),把所有父類(lèi)里面的f函數(shù)都屏蔽了。在虛表中父類(lèi)f函數(shù)的位置全部換成了子類(lèi)f函數(shù)的地址。因此在輸出時(shí)父類(lèi)的f函數(shù)沒(méi)有了,全部是子類(lèi)f函數(shù)的輸出。

- EOF -

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多

    国产成人高清精品尤物| 国产欧美日产中文一区| 五月天丁香婷婷狠狠爱| 日本加勒比在线观看一区| 久久99热成人网不卡| 日韩精品中文在线观看| 久久大香蕉精品在线观看| 亚洲另类欧美综合日韩精品| 樱井知香黑人一区二区| 真实偷拍一区二区免费视频| 年轻女房东2中文字幕| 91亚洲精品国产一区| 欧美欧美欧美欧美一区| 日韩中文字幕在线不卡一区| 国产中文另类天堂二区| 日本加勒比在线观看一区| 国语对白刺激高潮在线视频| 午夜福利视频偷拍91| 色婷婷国产熟妇人妻露脸| 又黄又硬又爽又色的视频| 久热久热精品视频在线观看| 午夜福利92在线观看| 激情三级在线观看视频| 91免费一区二区三区| 丰满人妻一二区二区三区av | 日本女优一色一伦一区二区三区| 国产亚洲系列91精品| 日本不卡一区视频欧美| 亚洲中文字幕剧情在线播放| 欧美一区二区三区十区| 国产原创激情一区二区三区| 老司机亚洲精品一区二区| 熟妇人妻av中文字幕老熟妇| 99久久精品免费精品国产| 日本91在线观看视频| 色偷偷亚洲女人天堂观看| 日韩成人午夜福利免费视频| 亚洲国产成人av毛片国产| 99国产精品国产精品九九| 隔壁的日本人妻中文字幕版| 午夜成年人黄片免费观看|

    AI助手

    阅读时有疑惑?点击向AI助手提问吧

    联系客服

    微信扫码,添加客服企业微信

    客服QQ:

    1732698931

    联系电话:4000-999-276

    客服工作时间9:00-18:00,晚上非工作时间,请在微信或QQ留言,第二天客服上班后会立即联系您。