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

分享

從內(nèi)存分布角度解釋“虛”原理

 海闊天空7815 2019-08-22

虛數(shù)?虛繼承?虛函數(shù)?

從內(nèi)存分布角度解釋”虛“原理?

看到這個(gè)題目的時(shí)候,學(xué)法的我表情是這樣的。

然而,我樸素的法感情告訴我這樣的內(nèi)容難不倒我一個(gè)法律人。

幸好,我還有搜索引擎還有同組同學(xué)的幫助。

讓我們看看”虛“到底是什么~

1.虛繼承

我們從目的和實(shí)現(xiàn)原理方面來看虛繼承

什么?虛繼承還有目的?來人啊,快把這要謀害我樸素法感情的人拿下!

1.1虛繼承的目的

        虛繼承是解決C++多重繼承問題的一種手段,從不同途徑繼承來的同一基類,會(huì)在子類中存在多份拷貝。

這將存在兩個(gè)問題:

其一,浪費(fèi)存儲(chǔ)空間。

其二,存在二義性問題。

通常可以將派生類對(duì)象的地址賦值給基類對(duì)象,實(shí)現(xiàn)的具體方式是,將基類指針指向繼承類(繼承類有基類的拷貝)中的基類對(duì)象的地址,但是多重繼承可能存在一個(gè)基類的多份拷貝,這就出現(xiàn)了二義性。

1.2一般繼承的實(shí)現(xiàn)原理

那么虛繼承是通過什么方式解決這兩個(gè)問題的呢?

我們要從內(nèi)存分布的角度來解釋原理。

因此需要知道一點(diǎn)visual studio開發(fā)人員命令行的知識(shí)。

我們首先從VS安裝目錄中打開開發(fā)人員命令行

進(jìn)入到對(duì)應(yīng)項(xiàng)目的目錄,然后輸入命令

cl -d1reportAllClassLayout yuan.cpp

這樣命令行界面就會(huì)給出該cpp里定義的所有類的內(nèi)存布局

如果想要特定類的內(nèi)存布局,可以輸入命令

cl -d1reportSingleClassLayout[類名] yuan.cpp

有了這樣的技術(shù)支持,我們就可以來探究虛繼承的內(nèi)存分布了。


1.2.1普通繼承的內(nèi)存布局

我們可以用visual studio新建項(xiàng)目,新建yuan.cpp,輸入如下代碼

打開開發(fā)人員命令行,進(jìn)入項(xiàng)目的目錄,輸入

cl -d1reportAllClassLayout yuan.cpp

可以得到我們定義的ABCD類的布局

可以看到,普通繼承時(shí)

類D包含的成員有(DataA,DataB,DataA,DataC,DataD)

int DataA出現(xiàn)了兩次,因此類D的內(nèi)存大小為20

因此出現(xiàn)了內(nèi)存的浪費(fèi)和二義性問題。

1.2.2虛繼承的內(nèi)存布局

我們將繼承方式改為虛繼承,代碼如下

使用命令行查看類ABCD新的內(nèi)存布局

可以預(yù)見A的內(nèi)存布局并不會(huì)改變。

而B和C占用的內(nèi)存從8變?yōu)?2,因?yàn)槠渲卸嗔艘粋€(gè)指針成員vbptr,vbptr指向了vbtable,我們將vbptr稱為虛指針,將vbtable稱為虛表。

再來看看D的內(nèi)存分布

D占用的內(nèi)存從20變?yōu)?4,但D中的成員相比于普通繼承只有一個(gè)DataA,而多了兩個(gè)分別繼承自B和C的虛指針vbptr。

那么虛指針到底是什么呢?

D的內(nèi)存布局其實(shí)已經(jīng)為我們提供了解答,我們可以看到兩個(gè)指針分別指向兩個(gè)虛表,虛表中記錄了vbptr與本類的偏移地址。

在本例子中,類B的vbptr指向了虛表D::$vbtable$@B@,虛表表明公共基類A的成員變量dataA距離類B開始處的位移為20,這樣就找到了成員變量dataA,類C的指針也對(duì)應(yīng)指向虛表,而虛表最終表示的偏移和B的虛表相同,這樣D中的成員就只有一個(gè)DataA,解決了二義性的問題。

但是我們可以看到,實(shí)際上使用虛繼承后BCD類的占用的內(nèi)存都變得更多了,并沒有解決內(nèi)存浪費(fèi)的問題。

這是因?yàn)槲覀冾怉的成員只有一個(gè)int類變量,如果A中的成員更復(fù)雜,占用更多的內(nèi)存,使用虛繼承時(shí)內(nèi)存的占用要比普通繼承少很多。

在寫完這些,我陷入的對(duì)自己人生的懷疑“我是誰,我在哪,我在干什么?然而這些都不能阻擋我接下來學(xué)習(xí)虛函數(shù)的熱情

2.虛函數(shù)

2.1虛函數(shù)的目的

在同一類中是不能定義兩個(gè)名字相同、參數(shù)個(gè)數(shù)和類型都相同的函數(shù)的,否則就是“重復(fù)定義”。

但是在類的繼承層次結(jié)構(gòu)中,在不同的層次中可以出現(xiàn)名字相同、參數(shù)個(gè)數(shù)和類型都相同而功能不同的函數(shù)。

人們提出這樣的設(shè)想,能否用同一個(gè)調(diào)用形式,既能調(diào)用派生類又能調(diào)用基類的同名函數(shù)。在程序中不是通過不同的對(duì)象名去調(diào)用不同派生層次中的同名函數(shù),而是通過指針調(diào)用它們。

例如,我們?cè)谖鰳?gòu)類的時(shí)候,一定是想要調(diào)用該類的析構(gòu)函數(shù),而不是基類的析構(gòu)函數(shù),否則有可能導(dǎo)致部分內(nèi)存沒有釋放。

C++中的虛函數(shù)就是用來解決這個(gè)問題的。虛函數(shù)的作用是允許在派生類中重新定義與基類同名的函數(shù),并且可以通過基類指針或引用來訪問基類和派生類中的同名函數(shù)。簡(jiǎn)單來說,虛函數(shù)是為了實(shí)現(xiàn)多態(tài)性。

2.2虛函數(shù)的實(shí)現(xiàn)原理

我們?nèi)詮膬?nèi)存分布的角度來探究虛函數(shù)的實(shí)現(xiàn)

2.2.1一般繼承

我們?nèi)源蜷_之前的項(xiàng)目,更改yuan.cpp的代碼如下

B類并沒有對(duì)繼承自A類函數(shù)進(jìn)行更改,我們調(diào)用VS開發(fā)者命令行

在項(xiàng)目目錄下執(zhí)行cl –d1reportAllClassLayout yuan.cpp

得到對(duì)應(yīng)AB類的內(nèi)存布局

可以看到,和虛繼承類似,有虛函數(shù)的類中的成員會(huì)多一個(gè)虛指針vfptr,虛指針指向虛函數(shù)表vftable。

在本例中,類A的虛指針指向A::$vftable@,這個(gè)虛表順序排列著我們?cè)陬怉中定義的f(),g(),h()函數(shù)。

由于我們沒有在子類B中對(duì)函數(shù)進(jìn)行定義的覆蓋,所以B的虛表中函數(shù)仍是A類中的f(),g(),h()函數(shù)。

現(xiàn)在我們更改代碼如下,在B類的定義中重新定義繼承的f()函數(shù)。

我們?cè)陬怋中對(duì)f()函數(shù)進(jìn)行了重新定義

再來看類AB的內(nèi)存布局

A類的虛表并不會(huì)變化,但B類的虛表發(fā)生了變化,具體是B類原本0位置的&A::f&B::f覆蓋了。

因此如果我們聲明一個(gè)基類的指針,使指針指向子類,通過指針調(diào)用f()函數(shù),我們會(huì)調(diào)用B類虛表中的&B::f,從而實(shí)現(xiàn)了多態(tài)

如果我們只對(duì)g()進(jìn)行重新定義,虛表會(huì)變成怎樣呢?

可以看出,虛表中函數(shù)的順序是與基類中定義順序相同,如果我們?cè)谧宇愔袑?duì)某個(gè)函數(shù)進(jìn)行重新定義,新的函數(shù)會(huì)覆蓋原本函數(shù)但并不會(huì)改變順序。

2.2.2多重繼承

假如子類繼承自多個(gè)父類,虛函數(shù)表又是如何實(shí)現(xiàn)的

更改代碼如下

我們定義了新的基類C,并在B中對(duì)父類的f()進(jìn)行覆蓋定義,并新定義虛函數(shù)k()

我們重新來看B的內(nèi)存布局

B中的成員理所當(dāng)然的有繼承自A和C的兩個(gè)虛指針。

繼承自A的虛指針指向虛函數(shù)表B::$vftable@A@

其中的成員不僅有&B::f,&A::g,&A::h,還有B中新定義的虛函數(shù)。

而繼承自C的虛指針指向虛函數(shù)表C::$vftable@C@

其中的成員為C的兩個(gè)虛函數(shù)。

也就是說B新定義的虛函數(shù)只會(huì)存放在繼承的第一個(gè)虛函數(shù)表中,并且在虛表中的位置要放到基類的虛函數(shù)之后。

3.總結(jié)

總的來說

虛繼承是為了解決多代繼承中的二義性和內(nèi)存浪費(fèi)的問題。

虛函數(shù)是為了解決多態(tài)性的問題。

二者都是通過虛指針虛表來實(shí)現(xiàn)的。

當(dāng)然以上的話以我樸素的法感情看來他們依然是天書,但是我相信我對(duì)虛函數(shù)與虛繼承的理解已經(jīng)比之前好很多了。

另外預(yù)祝大家大作業(yè)寫bugDebug順利!

by 伊藤優(yōu)香

and   孟令寰

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(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)遵守用戶 評(píng)論公約

    類似文章 更多

    最新午夜福利视频偷拍| 国产传媒精品视频一区| 国产精品午夜视频免费观看| 日韩欧美一区二区不卡看片| 狠狠干狠狠操在线播放| 欧洲偷拍视频中文字幕| 国产亚洲精品俞拍视频福利区| 伊人久久青草地婷婷综合| 亚洲精品偷拍视频免费观看| 国产在线一区二区三区不卡| 国产原创激情一区二区三区| 国产偷拍盗摄一区二区| 欧美欧美日韩综合一区| 国产内射一级一片内射高清视频| 国产又猛又大又长又粗| 日韩精品视频一二三区| 欧美日韩国产另类一区二区| 91欧美日韩一区人妻少妇| 国内精品伊人久久久av高清| 国产肥女老熟女激情视频一区| 亚洲一区二区欧美在线| 精品精品国产欧美在线| 国内精品一区二区欧美| 成人免费高清在线一区二区| 亚洲熟妇熟女久久精品 | 国产日韩精品激情在线观看| 久久综合狠狠综合久久综合| 91人妻久久精品一区二区三区| 九九热精品视频免费在线播放| 日韩午夜老司机免费视频 | 久久亚洲国产视频三级黄| 激情国产白嫩美女在线观看| 欧美在线观看视频三区| 欧美日韩国产自拍亚洲| 欧美成人久久久免费播放| 日韩黄色大片免费在线| 亚洲中文字幕视频在线播放| 麻豆一区二区三区在线免费| 黄色片国产一区二区三区| 日韩中文字幕狠狠人妻| 美女黄色三级深夜福利|