C++深度探索虛函數(shù)指針示例
代碼描述:定義一個(gè)Person類為基類,ChinesePer 類與EnglishPer類都繼承于此基類。
class Person { public: void speak() { cout << "說人話" << endl; } private: int m_type = 1 ; }; class ChinesePer :public Person { public: void speak() { cout << "說中國話chinese..." << endl; } }; class EnglishPer :public Person { public: void speak() { cout << "說英國話english..." << endl; } };
先看看此時(shí)各個(gè)類占用的內(nèi)存信息:
int main() { int person_size = sizeof(Person); int Chineseper_size = sizeof(ChinesePer); int Englishper = sizeof(EnglishPer); }
可以看到三個(gè)類的大小都為4個(gè)字節(jié),占用的情況就是 類中的m_type變量。
將基類中的 speak() 函數(shù)加上virtual關(guān)鍵字 ,成為虛函數(shù)后再次查看內(nèi)存字節(jié)大小:
可以看到多出了4個(gè)字節(jié)大小的空間(X86),三個(gè)類的大小都為 8。其實(shí)就是多出了一個(gè)指針的大小,4個(gè)字節(jié) ,創(chuàng)建一個(gè)子類對象就可以明顯看出來:
可以得出結(jié)論一:繼承過來的成員變量 m_type(4個(gè)字節(jié)) + _vfptr(4個(gè)字節(jié)) = 8個(gè)字節(jié)。
繼續(xù)探索虛函數(shù)表的原理, 創(chuàng)建以下子類對象并通過父類指針指向子類對象調(diào)用speak函數(shù)發(fā)生多態(tài):
int main(){ ChinesePer chs; ChinesePer chs2; EnglishPer eng; Person *ptr = &chs; //父類指針指向子類對象 Person *ptr1 = &chs2; Person *ptr2 = ŋ ptr->speak(); ptr1->speak(); ptr2->speak(); }
以上代碼執(zhí)行后會發(fā)生多態(tài):
此時(shí)我們看看三個(gè)對象的內(nèi)存分布:
用圖片簡要描述一下就是:
在這里可以先得到結(jié)論二: 同一個(gè)子類的所有對象共享一個(gè)虛函數(shù)表,指向虛函數(shù)表的指針_vptr是相同的。
在內(nèi)存分布上查看一下 eng對象的虛函數(shù)指針地址情況:
可以看到該虛函數(shù)指針的地址上的值,存放的正是 該子類中的重寫函數(shù) speak()函數(shù)的地址。
如果把這個(gè)地址的值,修改為 Chineseper 類中的重寫函數(shù)speak() 的地址值,會發(fā)生什么?
手動(dòng)修改了eng對象中虛函數(shù)指針內(nèi)的地址值,將改值本來是存放的是 EnglishPer 類中的speak() 函數(shù)的地址,現(xiàn)在更改為 ChinesePer 類中speak() 函數(shù)的地址。
單步走發(fā)生多態(tài):
至此可以得出結(jié)論三:
當(dāng)基類函數(shù)加了virtual 關(guān)鍵字后,虛函數(shù)的調(diào)用方法是間接調(diào)用:先查虛函數(shù)表的地址(也就是指向虛函數(shù)表的指針 _vptr),再查虛函數(shù)表中的虛函數(shù)指針。
不妨在基類繼續(xù)添加兩個(gè)虛函數(shù)
class Person { public: virtual void speak() { cout << "說人話" << endl; } virtual void eat() { cout << "吃飯" << endl; } virtual void sleep() { cout << "睡覺" << endl; } private: int m_type =1 ; };
子類只重寫了speak函數(shù),查看一下chs對象的虛函數(shù)指針地址存放的值:
的確存放的還是各個(gè)函數(shù)的地址,且是連續(xù)存放的,因此在進(jìn)行查表調(diào)用虛函數(shù)的時(shí)候,也是每移動(dòng)4個(gè)字節(jié)指向的就是一個(gè)函數(shù)的指針地址。
可以簡要描述一下形式就很直觀了:
總結(jié):
1.增加了virtual 關(guān)鍵字的對象頭部4個(gè)字節(jié)是一個(gè)指針,指向了虛函數(shù)表的地址(單繼承情況下)。
2.同一個(gè)子類的所有對象共享一個(gè)虛函數(shù)表,指向虛函數(shù)表的指針_vptr是相同的。
3.當(dāng)基類函數(shù)加了virtual 關(guān)鍵字后,虛函數(shù)的調(diào)用方法是間接調(diào)用:先查虛函數(shù)表的地址(也就是指向虛函數(shù)表的指針 _vptr),再查虛函數(shù)表中的虛函數(shù)指針。
到此這篇關(guān)于C++深度探索虛函數(shù)指針示例的文章就介紹到這了,更多相關(guān)C++虛函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言 module_init函數(shù)與initcall案例詳解
這篇文章主要介紹了C語言 module_init函數(shù)與initcall案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08淺析C++模板類型中的原樣轉(zhuǎn)發(fā)和可變參數(shù)的實(shí)現(xiàn)
可變參數(shù)模板(variadic templates)是C++11新增的強(qiáng)大的特性之一,它對模板參數(shù)進(jìn)行了高度泛化,能表示0到任意個(gè)數(shù)、任意類型的參數(shù),這篇文章主要介紹了C++可變參數(shù)模板的展開方式,需要的朋友可以參考下2022-08-08C++ 輸入一行數(shù)字(含負(fù)數(shù))存入數(shù)組中的案例
這篇文章主要介紹了C++ 輸入一行數(shù)字(含負(fù)數(shù))存入數(shù)組中的案例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12C++使用string的大數(shù)減法運(yùn)算(2)
這篇文章主要為大家詳細(xì)介紹了C++使用string的大數(shù)減法運(yùn)算,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09C++實(shí)現(xiàn)LeetCode(158.用Read4來讀取N個(gè)字符之二 - 多次調(diào)用)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(158.用Read4來讀取N個(gè)字符之二 - 多次調(diào)用),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07