php 網(wǎng)站 項(xiàng)目cilimao磁力貓搜索引擎
目錄
1.虛表指針與虛表?
?2.多態(tài)原理剖析
1.虛表指針與虛表?
🍪類(lèi)的大小計(jì)算規(guī)則
- 一個(gè)類(lèi)的大小,實(shí)際就是該類(lèi)中成員變量之和,需要注意內(nèi)存對(duì)齊
- 空類(lèi):編譯器給空類(lèi)一個(gè)字節(jié)來(lái)唯一標(biāo)識(shí)這個(gè)類(lèi)的對(duì)象
對(duì)于下面的Base類(lèi),它的大小應(yīng)該是類(lèi)中成員變量之和,一個(gè)int成員,一個(gè)char成員,根據(jù)結(jié)構(gòu)體內(nèi)存對(duì)齊規(guī)則,sizeof(Base) = 8byte
class Base
{
public:virtual void func1(){cout << "func1()" << endl;}
private:int _b = 1;char _ch;
};
成員函數(shù)為虛函數(shù)?
成員函數(shù)是普通函數(shù)?
但是代碼的運(yùn)行結(jié)果為sizeof(Base) = 12byte,與上面的分析結(jié)果不一致
Base類(lèi)中的成員函數(shù)使用virtual修飾,可以推斷包含虛函數(shù)的類(lèi)大小計(jì)算規(guī)則和包含普通函數(shù)的類(lèi)大小計(jì)算規(guī)則可能存在差異
我們創(chuàng)建一個(gè)Base對(duì)象,進(jìn)行進(jìn)一步分析
從監(jiān)視窗口,可以發(fā)現(xiàn),實(shí)例化的Base對(duì)象成員構(gòu)成,除了兩個(gè)成員變量外,還有一個(gè)數(shù)組指針,而數(shù)組成員又是指針類(lèi)型,所以準(zhǔn)確來(lái)說(shuō),_vfptr是一個(gè)指針數(shù)組指針
🍪虛表指針和虛表
虛表指針:對(duì)象中的這個(gè)指針叫做虛函數(shù)表指針(v--virtual,f--function)。
虛表:一個(gè)含有虛函數(shù)的類(lèi)中至少有一個(gè)虛函數(shù)表指針,因?yàn)樘摵瘮?shù)的地址要被放到虛函數(shù)表(虛表)中
📖Note:
- 虛函數(shù)表本質(zhì)是一個(gè)存虛函數(shù)指針的指針數(shù)組,一般這個(gè)數(shù)組最后面放了一個(gè)nullptr
虛表存的是虛函數(shù)指針,不是虛函數(shù),虛函數(shù)和普通函數(shù)一樣的,都是存在代碼段的,只是虛函數(shù)的指針存在虛表中,可以通過(guò)這個(gè)指針找到虛函數(shù)
實(shí)例化對(duì)象中存的不是虛表,存的是虛表指針,通過(guò)這個(gè)指針可以找到虛表。
接下來(lái)執(zhí)行三個(gè)操作
- Base增加一個(gè)虛函數(shù)func2和一個(gè)普通函數(shù)fun3。
- 增加一個(gè)派生類(lèi)Derive去繼承Base
- Derive中重寫(xiě)func1?
class Base
{
public:virtual void func1(){cout << "func1()" << endl;}virtual void func2(){cout << "func2()" << endl;}// 普通函數(shù)void func3(){cout << "func3()" << endl;}
private:int _b = 1;char _ch;
};class Derive : public Base
{
public:virtual void func1(){cout << "Derive::func1()" << endl;}
private:int _d = 2;
};
從監(jiān)視窗口可以發(fā)現(xiàn)
1??基類(lèi)的虛表指針值_vfptr? !=? 派生類(lèi)的虛表指針值_vfptr
2??基類(lèi)的普通函數(shù)func3不會(huì)存入虛表之中,繼承之后也不會(huì)存入派生類(lèi)的虛表
3??派生類(lèi)中對(duì)func1完成了重寫(xiě),d的虛表中存的是重寫(xiě)的Derive::func1,所以虛函數(shù)的重寫(xiě)(語(yǔ)法層)也叫作覆蓋(原理層),覆蓋就是指虛表中虛函數(shù)的覆蓋。
🍪派生類(lèi)的虛表指針總結(jié):
- 派生類(lèi)對(duì)象中也有一個(gè)虛表指針,派生類(lèi)繼承的成員包括虛表指針,但需要注意基類(lèi)和派生類(lèi)的虛表不是同一份
- 基類(lèi)中的虛函數(shù),派生類(lèi)繼承之后放進(jìn)了虛表,基類(lèi)中的普通函數(shù),派生類(lèi)繼承之后不會(huì)放進(jìn)虛表
派生類(lèi)自己新增的虛函數(shù)按其在派生類(lèi)中的聲明次序增加到派生類(lèi)虛表的最后,如下圖所示
派生類(lèi)的虛表生成過(guò)程:
?2.多態(tài)原理剖析
基于上面創(chuàng)建的基類(lèi)Base和派生類(lèi)Derive,執(zhí)行以下代碼,觀察執(zhí)行結(jié)果?
🍪分析:
- func3是基類(lèi)Base中的定義的普通函數(shù)
- func1是基類(lèi)Base中定義的虛函數(shù),且派生類(lèi)完成了對(duì)func1的重寫(xiě),構(gòu)成多態(tài)
🍪普通函數(shù)的調(diào)用,只與調(diào)用函數(shù)的對(duì)象的類(lèi)型有關(guān)
前兩次對(duì)func3的調(diào)用都是Base*類(lèi)型的指針進(jìn)行調(diào)用
🍪多態(tài)調(diào)用,與函數(shù)調(diào)用者指向的整個(gè)對(duì)象有關(guān)
- 第一次對(duì)func1的調(diào)用:ptr指向的是一個(gè)Base對(duì)象,對(duì)虛函數(shù)func1的調(diào)用需要到_vfptr指向的虛表中查找func1函數(shù)的地址進(jìn)行調(diào)用,最終調(diào)用的是Base類(lèi)中的函數(shù)func1
- 第二次對(duì)func1的調(diào)用:ptr指向的是Derive對(duì)象中Base的切片,對(duì)虛函數(shù)func1的調(diào)用仍然需要到_vfptr指向的虛表中查找func1函數(shù)的地址進(jìn)行調(diào)用,但是這一次,_vfptr指向的虛表中,func1函數(shù)的地址已經(jīng)更改成了Derive類(lèi)中重寫(xiě)的func1函數(shù)地址,所以最終調(diào)用的是Derive中重寫(xiě)的func1函數(shù)