国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

C++多態(tài)底層刨析(虛函數(shù)指針,虛函數(shù)表)

callmewhy / 3155人閱讀

摘要:當(dāng)子類(lèi)繼承了父類(lèi)并且子類(lèi)重寫(xiě)了父類(lèi)的虛函數(shù)之后,我們可以看到此時(shí)子類(lèi)中虛函數(shù)指針對(duì)應(yīng)的虛函數(shù)表中存的是子類(lèi)經(jīng)過(guò)重寫(xiě)的函數(shù)了。

前言:相信小伙伴們?cè)趯W(xué)習(xí)到C++面向?qū)ο筇匦灾坏亩鄳B(tài)的時(shí)候,都或多或少有一些疑惑。搞不清楚多態(tài)在底層是如何實(shí)現(xiàn)的,今天我就帶大家刨析一下多態(tài)的底層實(shí)現(xiàn),了解一下虛函數(shù)指針和虛函數(shù)表到底是什么東西?(注意本文操作環(huán)境是VS2019 x86架構(gòu) 32位機(jī)器)

1 、多態(tài)的定義和分類(lèi)

1.1 多態(tài)的定義

1.1.1 定義:
多態(tài)按字面的意思就是多種形態(tài)。當(dāng)類(lèi)之間存在層次結(jié)構(gòu),并且類(lèi)之間是通過(guò)繼承關(guān)聯(lián)時(shí),就會(huì)用到多態(tài)。
C++ 多態(tài)意味著調(diào)用成員函數(shù)時(shí),會(huì)根據(jù)調(diào)用函數(shù)的對(duì)象的類(lèi)型來(lái)執(zhí)行不同的函數(shù)。
----------來(lái)自菜鳥(niǎo)教程

1.2 多態(tài)的分類(lèi)

1.2.1 多態(tài)分為兩類(lèi):
·靜態(tài)多態(tài):函數(shù)重載和運(yùn)算符重載屬于靜態(tài)重載,復(fù)用函數(shù)名
·動(dòng)態(tài)多態(tài):派生類(lèi)和虛函數(shù)實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)
1.2.2 靜態(tài)多態(tài)和動(dòng)態(tài)多態(tài)的區(qū)別:
·靜態(tài)多態(tài)的函數(shù)地址早綁定–編譯階段確定函數(shù)地址
·動(dòng)態(tài)多態(tài)的函數(shù)地址晚綁定–運(yùn)行階段確定函數(shù)地址

2、靜態(tài)多態(tài)代碼演示

2.1 靜態(tài)多態(tài)代碼:

#includeusing namespace std;class Father{public:    void speak() {        cout << "爸爸在說(shuō)話(huà)!" << endl;    }};class Son :public Father{public:    void speak() {        cout << "兒子在說(shuō)話(huà)!" << endl;    }};//執(zhí)行說(shuō)話(huà)函數(shù)//地址早被綁定 在編譯階段確定函數(shù)地址void doSpeak(Father &father)//父類(lèi)引用接收子類(lèi)對(duì)象{    father.speak();}void test01(){    Son son;    doSpeak(son);}int main(){    test01();    return 0;}

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

2.3 分析:
在此案例中,派生類(lèi)和基類(lèi)中都出現(xiàn)了speak函數(shù),當(dāng)用父類(lèi)指針或者引用接收子類(lèi)對(duì)象時(shí),程序會(huì)執(zhí)行基類(lèi)中的同名函數(shù),這是為什么呢?因?yàn)楦割?lèi)中的speak函數(shù)地址在編譯期間就被綁定,所以在執(zhí)行程序時(shí)無(wú)論傳遞的是哪種對(duì)象,執(zhí)行的都是基類(lèi)中的speak函數(shù)。這就是靜態(tài)動(dòng)態(tài)的弊端,那么如果想實(shí)現(xiàn)傳入哪種對(duì)象就執(zhí)行哪種類(lèi)的函數(shù),這就需要用到動(dòng)態(tài)多態(tài)了。

3 、動(dòng)態(tài)多態(tài)的代碼刨析

動(dòng)態(tài)多態(tài)滿(mǎn)足條件:
1、有繼承關(guān)系
2、子類(lèi)重寫(xiě)父類(lèi)的虛函數(shù)
動(dòng)態(tài)多態(tài)的使用:
父類(lèi)的指針或者引用指向子類(lèi)對(duì)象

3.1 動(dòng)態(tài)多態(tài)代碼演示

3.1.1動(dòng)態(tài)多態(tài)代碼

#includeusing namespace std;class Father{public:    virtual void speak() {        cout << "爸爸在說(shuō)話(huà)!" << endl;    }};class Son :public Father{public:    void speak() {        cout << "兒子在說(shuō)話(huà)!" << endl;    }};//執(zhí)行說(shuō)話(huà)函數(shù)//地址早被綁定 在編譯階段確定函數(shù)地址void doSpeak(Father &father)//父類(lèi)引用接收子類(lèi)對(duì)象{    father.speak();}void test01(){    Son son;    doSpeak(son);}int main(){    test01();    return 0;}

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

3.1.3 分析:
靜態(tài)多態(tài)變?yōu)閯?dòng)態(tài)多態(tài)只需要給父類(lèi)的函數(shù)加上virtual關(guān)鍵字變?yōu)樘摵瘮?shù)。

3.2 代碼刨析

小知識(shí):在C++中空類(lèi)也占內(nèi)存,占一個(gè)字節(jié)的空間

3.2.1
我們先來(lái)看一下父類(lèi)的函數(shù)前加上virtual關(guān)鍵字,父類(lèi)的內(nèi)存占用有什么變化?

通過(guò)運(yùn)行發(fā)現(xiàn)此時(shí)父類(lèi)所占的空間變成了4個(gè)字節(jié),那么這四個(gè)字節(jié)到底是存了什么????其實(shí)聰明的小伙伴們可能已經(jīng)猜出來(lái)這四個(gè)字節(jié)是什么了,沒(méi)錯(cuò)存的就是一個(gè)指針。這個(gè)指針就叫虛函數(shù)指針,簡(jiǎn)寫(xiě)為vfptr(virtual function pointer). 對(duì)于一個(gè)類(lèi)來(lái)說(shuō),如果類(lèi)中存在虛函數(shù),那么編譯器就會(huì)自動(dòng)在類(lèi)中加一條生成虛函數(shù)指針的語(yǔ)句(void * vfptr),并且在類(lèi)的構(gòu)造函數(shù)中為虛函數(shù)指針進(jìn)行賦值(vfptr=&Father::vtal),此時(shí)這個(gè)虛函數(shù)指針就會(huì)指向虛函數(shù)表。所以,如果對(duì)象存在虛函數(shù),那么編譯器就會(huì)生成一個(gè)指向虛函數(shù)表的指針,所有的虛函數(shù)都存在于這個(gè)表中,虛函數(shù)表就可以理解為一個(gè)數(shù)組,每個(gè)單元用來(lái)存放虛函數(shù)的地址。
3.2.2
此時(shí)我們?cè)诟割?lèi)中寫(xiě)兩個(gè)虛函數(shù)
然后打開(kāi)vs2019的調(diào)試功能查看一下對(duì)象father可以看到

此時(shí)可以發(fā)現(xiàn)父類(lèi)對(duì)象確實(shí)有一個(gè)vfptr指針,這個(gè)指針對(duì)應(yīng)的
表里就是儲(chǔ)存著兩個(gè)虛函數(shù)的地址,這兩個(gè)函數(shù)都是屬于父類(lèi)的。
3.2.3
當(dāng)子類(lèi)繼承了父類(lèi)并且子類(lèi)重寫(xiě)了父類(lèi)的虛函數(shù)之后,我們可以看到:

此時(shí)子類(lèi)中虛函數(shù)指針對(duì)應(yīng)的虛函數(shù)表中存的是子類(lèi)經(jīng)過(guò)重寫(xiě)的函數(shù)了。所以當(dāng)傳入一個(gè)子類(lèi)對(duì)象時(shí)通過(guò)查詢(xún)子類(lèi)vfptr找到對(duì)應(yīng)的虛函數(shù)表,從而找到其中存的函數(shù)地址去執(zhí)行,這也就是為什么動(dòng)態(tài)多態(tài)可以根據(jù)傳入對(duì)象的不同來(lái)執(zhí)行不同的語(yǔ)句。

3.2.4 畫(huà)圖演示

4、使用VS自帶的開(kāi)發(fā)人員工具檢驗(yàn)

4.1 找到VS2019開(kāi)發(fā)人員工具

4.2 查看有虛函數(shù)的父類(lèi)布局

4.3 查看子類(lèi)重寫(xiě)虛函數(shù)之后子類(lèi)的布局


由此證明,我們的結(jié)論是正確的!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/119812.html

相關(guān)文章

  • 談?wù)凧ava的面向?qū)ο?/b>

    摘要:也就是說(shuō),一個(gè)實(shí)例變量,在的對(duì)象初始化過(guò)程中,最多可以被初始化次。當(dāng)所有必要的類(lèi)都已經(jīng)裝載結(jié)束,開(kāi)始執(zhí)行方法體,并用創(chuàng)建對(duì)象。對(duì)子類(lèi)成員數(shù)據(jù)按照它們聲明的順序初始化,執(zhí)行子類(lèi)構(gòu)造函數(shù)的其余部分。 類(lèi)的拷貝和構(gòu)造 C++是默認(rèn)具有拷貝語(yǔ)義的,對(duì)于沒(méi)有拷貝運(yùn)算符和拷貝構(gòu)造函數(shù)的類(lèi),可以直接進(jìn)行二進(jìn)制拷貝,但是Java并不天生支持深拷貝,它的拷貝只是拷貝在堆上的地址,不同的變量引用的是堆上的...

    ormsf 評(píng)論0 收藏0
  • C++基礎(chǔ)語(yǔ)法(五)繼承——萬(wàn)字總結(jié),干貨滿(mǎn)滿(mǎn)

    摘要:繼承方式繼承方式限定了基類(lèi)成員在派生類(lèi)中的訪問(wèn)權(quán)限,包括公有的私有的和受保護(hù)的。所以子類(lèi)給父類(lèi)引用賦值也是可以的,相當(dāng)于給子類(lèi)對(duì)象中繼承的父類(lèi)部分起了別名。如圖成員函數(shù)也是如此,當(dāng)子類(lèi)與父類(lèi)具有函數(shù)名相同的函數(shù)時(shí),還是符合就近原則。 ...

    smartlion 評(píng)論0 收藏0
  • C++學(xué)習(xí)資料和視頻

    摘要:博主在公眾號(hào)后臺(tái)設(shè)置了關(guān)鍵字回復(fù),回復(fù)下面的里面的內(nèi)容,可免費(fèi)獲得學(xué)習(xí)視頻和資料。 博主在公眾號(hào)后臺(tái)設(shè)置了關(guān)鍵字回復(fù), 回復(fù)下面的【】里面的內(nèi)容, 可免費(fèi)獲得C++學(xué)習(xí)視頻和資料。 如回復(fù):C++基礎(chǔ) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? 【C++】 【1】...

    wangshijun 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<