C++虛函數(shù)的實(shí)現(xiàn)機(jī)制分析
本文針對(duì)C++的虛函數(shù)的實(shí)現(xiàn)機(jī)制進(jìn)行較為深入的分析,具體如下:
1、簡(jiǎn)單地說(shuō),虛函數(shù)是通過(guò)虛函數(shù)表實(shí)現(xiàn)的。那么,什么是虛函數(shù)表呢?
事實(shí)上,如果一個(gè)類中含有虛函數(shù),則系統(tǒng)會(huì)為這個(gè)類分配一個(gè)指針成員指向一張?zhí)摵瘮?shù)表(vtbl),表中每一項(xiàng)指向一個(gè)虛函數(shù)的地址,實(shí)現(xiàn)上就是一個(gè)函數(shù)指針的數(shù)組。
例如下面這個(gè)例子:
class Parent { public: virtual void foo1() { } virtual void foo1() { } void foo1(); }; class Child1 { public: void foo1() { } void foo3(); }; class Child2 { public: void foo1() {} void foo2() {} void foo3(); };
下面列出了各個(gè)類的虛函數(shù)表(vtbl)的內(nèi)容。
Parent類的vtbl:Parent::foo1( )的地址、Parent::foo1( )。
Child1類的vtbl:Child1::foo1( )的地址、Parent::foo1( )。
Child2類的vtbl:Child1::foo1( )的地址、Child2::foo1( )。
2、可以看出,虛函數(shù)表既有繼承性,又有多態(tài)性。每個(gè)派生類的vtbl繼承了它各個(gè)基類的vtbl,如果基類vtbl中包含某一項(xiàng),則派生類的vtbl中也將包含同樣的一項(xiàng),但是兩項(xiàng)的值可能不同。如果派生類覆蓋了該項(xiàng)對(duì)應(yīng)的虛函數(shù),則派生類vtbl的該指針先指向重載后的虛函數(shù),沒有重載的話,則沿用基類的值。
3、在類對(duì)象的內(nèi)存布局中,首先是該類的vtbl指針,然后才是對(duì)象數(shù)據(jù)。在通過(guò)對(duì)象指針調(diào)用一個(gè)虛函數(shù)時(shí),編譯器生成的代碼將先獲取對(duì)象類的vtbl指針,然后調(diào)用vtbl中對(duì)應(yīng)的項(xiàng)。對(duì)于通過(guò)對(duì)象指針調(diào)用的情況,在編譯期間無(wú)法確定指針指向的是基類對(duì)象還是派生類對(duì)象,或者是哪個(gè)派生類的對(duì)象。但是在運(yùn)行期間執(zhí)行到調(diào)用語(yǔ)句時(shí),這一點(diǎn)已經(jīng)確定,編譯后的調(diào)用代碼能夠根據(jù)具體對(duì)象獲取正確的vtbl,調(diào)用正確地虛函數(shù),從而實(shí)現(xiàn)多態(tài)性。
4、分析一下這里的思想所在:
問(wèn)題的實(shí)質(zhì)是這樣,對(duì)于發(fā)出虛函數(shù)調(diào)用的這個(gè)對(duì)象指針,在編譯期間缺乏更多的信息,而在運(yùn)行期間具備足夠的信息,但那時(shí)已不再進(jìn)行綁定了,怎么在二者之間做一個(gè)過(guò)渡呢?
把綁定所需的信息用一種通用的數(shù)據(jù)結(jié)構(gòu)記錄下來(lái),該數(shù)據(jù)結(jié)構(gòu)可以同對(duì)象指針相聯(lián)系,在編譯時(shí)只需要使用這個(gè)數(shù)據(jù)結(jié)構(gòu)進(jìn)行抽象的綁定,而在運(yùn)行期間將會(huì)得到真正的綁定。這個(gè)數(shù)據(jù)結(jié)構(gòu)就是vtbl??梢钥吹?,實(shí)現(xiàn)用戶所需的抽象和多態(tài)需要進(jìn)行后綁定,而編譯器又是通過(guò)抽象和多態(tài)實(shí)現(xiàn)后綁定的。
相關(guān)文章
c語(yǔ)言求出給定范圍內(nèi)的所有質(zhì)數(shù)
本文主要介紹了c語(yǔ)言求出給定范圍內(nèi)的所有質(zhì)數(shù)的小程序。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-04-04淺談C結(jié)構(gòu)和C++結(jié)構(gòu)之間的區(qū)別
這篇文章主要介紹了淺談C結(jié)構(gòu)和C++結(jié)構(gòu)之間的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04c++基礎(chǔ)語(yǔ)法:構(gòu)造函數(shù)與析構(gòu)函數(shù)
構(gòu)造函數(shù)用來(lái)構(gòu)造一個(gè)對(duì)象,主要完成一些初始化工作,如果類中不提供構(gòu)造函數(shù),編譯器會(huì)默認(rèn)的提供一個(gè)默認(rèn)構(gòu)造函數(shù)(參數(shù)為空的構(gòu)造函數(shù)就是默認(rèn)構(gòu)造函數(shù)) ;析構(gòu)函數(shù)是隱式調(diào)用的,delete對(duì)象時(shí)候會(huì)自動(dòng)調(diào)用完成對(duì)象的清理工作2013-09-09C++語(yǔ)言實(shí)現(xiàn)線性表之?dāng)?shù)組實(shí)例
這篇文章主要介紹了C++語(yǔ)言實(shí)現(xiàn)線性表之?dāng)?shù)組,實(shí)例分析了C++實(shí)現(xiàn)數(shù)組形式線性表的原理與方法,需要的朋友可以參考下2015-04-04C++常對(duì)象精講_const關(guān)鍵字的用法
用const修飾的聲明數(shù)據(jù)成員稱為常數(shù)據(jù)成員。變量或?qū)ο蟊?const修飾后其值不能被更新。因此被const修飾的變量或?qū)ο蟊仨氁M(jìn)行初始化2013-10-10C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之單鏈表操作詳解
鏈表是一種物理存儲(chǔ)結(jié)構(gòu)上非連續(xù)、非順序的存儲(chǔ)結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過(guò)鏈表中的指針鏈接次序?qū)崿F(xiàn)的。本文將和大家一起聊聊C語(yǔ)言中單鏈表的常用操作,感興趣的可以學(xué)習(xí)一下2022-07-07