最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++ 虛函數(shù)表圖文解析

 更新時間:2021年05月13日 09:22:09   作者:flight1111  
最近學了設計模式中的簡單工廠模式,對多態(tài)有了具體的認識。于是補了補多態(tài)、虛函數(shù)、虛函數(shù)表相關(guān)的知識,本文介紹了C++ 虛函數(shù)表,感興趣的了解一下

一、前言

一直以來,對虛函數(shù)的理解僅僅是,在父類中定義虛函數(shù),子類中可以重寫該虛函數(shù),并且父類指針可以指向子類對象,調(diào)用子類的虛函數(shù)(多態(tài))。在讀研階段經(jīng)歷的幾個項目中,自己所寫的類中并沒有用到虛函數(shù),對虛函數(shù)這個東西的強大之處并沒有太多體會。最近,學了設計模式中的簡單工廠模式,對多態(tài)有了具體的認識。于是,補了補多態(tài)、虛函數(shù)、虛函數(shù)表相關(guān)的知識,參考相關(guān)博客,加上自己的理解,整理了這篇博文。

二、含有虛函數(shù)類的內(nèi)存模型

以下面的類為例(32位平臺下):

class Father {
public:
	virtual void fun1() { cout << "Father::fun1()" << endl; }
	virtual void fun2() { cout << "Father::fun2()" << endl; }
	int i;
};

該類中含有兩個虛函數(shù)和一個成員變量i,輸出sizeof(Father),結(jié)果為8個字節(jié)。如果去掉virtual關(guān)鍵字,則結(jié)果為4個字節(jié)。也就是說,類中含有虛函數(shù),則該類會增加4個字節(jié),那這4個字節(jié)是什么變量所占據(jù)的呢?

答案是一個指針(我覺得應該是unsigned int*類型指針,這點不確定),在vs調(diào)試窗口中,可以看到該指針名為_vfptr,該指針稱為虛函數(shù)表指針。

類的內(nèi)存模型如下,_vptr指針和成員變量i各占4字節(jié),一共8字節(jié)。另外 ,-vptr指針一定在內(nèi)存模型前面。對于只有一個虛表指針的類來說,類內(nèi)存模型前4個字節(jié)就是虛表指針所占空間。

在這里插入圖片描述

三、虛函數(shù)表與虛函數(shù)表指針

上面提到_vfptr是虛函數(shù)表指針,那虛函數(shù)表是什么呢?

虛函數(shù)表其實就是一個指針數(shù)組,這個數(shù)組中存放著虛函數(shù)的地址,大概如下:

在這里插入圖片描述

最后一個類似于字符串的結(jié)束標志位,VS編譯器中為0。

這樣的話,虛函數(shù)表指針就很容易理解了,這個虛函數(shù)表指針指向該虛函數(shù)表,也就是虛函數(shù)指針的值就是上述指針數(shù)組的首地址。

在這里插入圖片描述

四、虛函數(shù)地址

函數(shù)存放在代碼區(qū),虛函數(shù)也不例外。虛函數(shù)表中存放的是虛函數(shù)地址,即代碼區(qū)虛函數(shù)的入口地址。

在這里插入圖片描述

五、多態(tài)

定義一個Father的子類Son,對虛函數(shù)fun1()進行重寫。

#include<iostream>
using namespace std;
class Father {
public:
	virtual void fun1() { cout << "Father::fun1()" << endl; }
	virtual void fun2() { cout << "Father::fun2()" << endl; }
	int i;
};

class Son :public Father {
	virtual void fun1() { cout << "Son::fun1()" << endl; }

};
int main()
{
	Son son;
	Father father;
	Father *p = &father;
	p->fun1();
	p->fun2();
    p=&son;
    p->fun1();
    p->fun2();
	return 0;
}

父類中有虛函數(shù),則子類同樣會有一個虛函數(shù)指針,這個指針指向一個新表,如下圖所示:

在這里插入圖片描述

Son類重寫了fun1(),未重寫fun2(),那么虛函數(shù)表中,第一個地址便是重寫的Son::fun1()的地址,第二個地址仍然是父類中Father::fun2()的地址。這里可以在vs調(diào)試模式下,查看father與son的虛函數(shù)表,son表中第二個元素值與father表中第二個元素值相同。

	Father *p = &father;
	p->fun1();
	p->fun2();

p指向Father對象father:

p->fun1():沿著框1->框3->框5的路徑,調(diào)用Father::fun1();

p->fun2():沿著框1->框4->框6的路徑,調(diào)用Father::fun2();

p=&son;
p->fun1();
p->fun2();

p指向子類對象son:

p->fun1():沿著框7->框9->框11的路徑,調(diào)用Son::fun1();

p->fun2():沿著框7->框10->框6的路徑,調(diào)用Father::fun2();

六、通過函數(shù)指針操作調(diào)用虛函數(shù)

現(xiàn)修改main函數(shù)

typedef void(*Fun)(void);
int main()
{

	Father father;
	Son son;
	printf("虛函數(shù)表地址_vfptr:%p\n", *(unsigned int*)(&father));
	printf("第一個虛函數(shù)地址e:%p\n", *(unsigned int*)*(unsigned int*)(&father));
	printf("第二個虛函數(shù)地址f:%p\n", *((unsigned int*)*(unsigned int*)(&father)+1));

	unsigned char* end = NULL;
	end = (unsigned char*)((unsigned int*)*(unsigned int*)(&father) + 2);
	printf("結(jié)束符地址d:%p\n", end);
	printf("結(jié)束符值:%d\n", *end);

	Fun pFun = NULL;
	pFun = (Fun)(*((unsigned int*)*(unsigned int*)(&father) + 1));
	pFun();
    
	return 0;
}

運行結(jié)果:

在這里插入圖片描述

先看一下vs調(diào)試模式下各變量的值

在這里插入圖片描述

將之前的圖修改一下,便于理解:

在這里插入圖片描述

紅框中,father中的_vfptr為0x1270234,對應上圖中的_vfptr,即虛函數(shù)表的地址;

數(shù)組[0]值為0x01261447,對應上圖中的e,即Father::fun1()的地址;

數(shù)組[1]值為0x0126141a,對應上圖中的f,即Father::fun2()的地址。

好了,現(xiàn)在來看一下程序中這些看起來很唬人的東西:

	printf("虛函數(shù)表地址_vfptr:%p\n", *(unsigned int*)(&father));
	printf("第一個虛函數(shù)地址e:%p\n", *(unsigned int*)*(unsigned int*)(&father));
	printf("第二個虛函數(shù)地址f:%p\n", *((unsigned int*)*(unsigned int*)(&father)+1));
	unsigned char* end = NULL;
	end = (unsigned char*)((unsigned int*)*(unsigned int*)(&father) + 2);

這里,直接用上圖中的符號進行分析,否則,說一通xx的地址、對xx解引用等等,容易把人搞暈。

(1)虛函數(shù)表的地址*(unsigned int*)(&father)

  • a0=&father
  • a1=(unsigned int *)a0
  • _vfptr=*a1

在這里插入圖片描述

注意,這里a0和a1的數(shù)值是一樣的,但只有把地址a0強制轉(zhuǎn)換成(unsigned int *)類型,解引用時系統(tǒng)才會從該地址向后解析4個字節(jié)空間,解析成一個unsinged int類型數(shù)據(jù)。

(2)第一個虛函數(shù)地址*(unsigned int*)*(unsigned int*)(&father)

  • b=(unsigned int*)_vfptr
  • e=*b

在這里插入圖片描述

(3)第二個虛函數(shù)地址*((unsigned int*)*(unsigned int*)(&father)+1)

  • c=b+1
  • f=*c

在這里插入圖片描述

(4)結(jié)束符地址(unsigned char*)((unsigned int*)*(unsigned int*)(&father) + 2)

  • 未強制轉(zhuǎn)換的d=b+2
  • 強制轉(zhuǎn)換的d=(unsigned char*)(b+2)

在這里插入圖片描述 

(5)通過函數(shù)指針調(diào)用虛函數(shù)

	Fun pFun = NULL;
	pFun = (Fun)(*((unsigned int*)*(unsigned int*)(&father) + 1));
	pFun();

在這里插入圖片描述

七、結(jié)語

這篇博文包含許多自己理解的內(nèi)容,并在此基礎上畫了圖解,如果有誤,還請指正。

八、參考

C++ 虛函數(shù)表解析

虛函數(shù)表詳解

C++ 虛函數(shù)詳解(虛函數(shù)表、vfptr)

到此這篇關(guān)于C++ 虛函數(shù)表圖文解析的文章就介紹到這了,更多相關(guān)C++ 虛函數(shù)表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++?OpenCV紅綠燈檢測Demo實現(xiàn)詳解

    C++?OpenCV紅綠燈檢測Demo實現(xiàn)詳解

    OpenCV(Open Source Computer Vision Library)是開源的計算機視覺和機器學習庫,提供了C++、 C、 Python、 Java接口,并支持Windows、 Linux、 Android、 Mac OS平臺,下面這篇文章主要給大家介紹了關(guān)于C++?OpenCV紅綠燈檢測Demo實現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • C++如何將字符串顛倒輸出

    C++如何將字符串顛倒輸出

    這篇文章主要介紹了C++如何將字符串顛倒輸出,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C語言double和float 實例分析

    C語言double和float 實例分析

    本文主要介紹了C語言中的浮點數(shù)(float,double),并通過實例代碼進行分析比較,希望能幫助學習相關(guān)知識的同學
    2016-07-07
  • C++封裝線程類的實現(xiàn)方法

    C++封裝線程類的實現(xiàn)方法

    這篇文章主要介紹了C++封裝線程類的實現(xiàn)方法,實例介紹了針對線程的創(chuàng)建、調(diào)用等方法的封裝操作,需要的朋友可以參考下
    2014-10-10
  • C++實現(xiàn)連連看游戲

    C++實現(xiàn)連連看游戲

    這篇文章主要為大家詳細介紹了C++實現(xiàn)連連看游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C++中的std::async()詳解

    C++中的std::async()詳解

    這篇文章主要給大家介紹了關(guān)于C++中std::async()的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11
  • c/c++那些你一定會出錯的數(shù)組筆試題匯總

    c/c++那些你一定會出錯的數(shù)組筆試題匯總

    這篇文章主要給大家匯總介紹了關(guān)于c/c++那些你一定會出錯的數(shù)組筆試題,除了基本數(shù)據(jù)類型之外,其余的都作為類對象,包括數(shù)組,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-10-10
  • 使用Qt實現(xiàn)旋轉(zhuǎn)動畫效果

    使用Qt實現(xiàn)旋轉(zhuǎn)動畫效果

    這篇文章主要為大家詳細介紹了如何使用Qt實現(xiàn)旋轉(zhuǎn)動畫效果,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-11-11
  • 一道面試題教你輕松玩轉(zhuǎn)C++指針

    一道面試題教你輕松玩轉(zhuǎn)C++指針

    下面小編就為大家?guī)硪黄钊肜斫鈉++指針的指針和指針的引用。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考,一起跟隨小編過來看看吧
    2021-09-09
  • C++實現(xiàn)會員管理程序

    C++實現(xiàn)會員管理程序

    這篇文章主要為大家詳細介紹了C++實現(xiàn)會員管理程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-07-07

最新評論

陆良县| 屯门区| 仪陇县| 湘乡市| 黑河市| 哈密市| 历史| 三明市| 揭阳市| 慈利县| 紫阳县| 疏勒县| 佛山市| 贵溪市| 泽州县| 阳谷县| 建平县| 荆州市| 泰宁县| 隆林| 周口市| 福州市| 泽普县| 辽阳县| 河南省| 松阳县| 上虞市| 古田县| 龙海市| 奉节县| 沿河| 三穗县| 泸水县| 北流市| 北海市| 金昌市| 洪湖市| 通道| 施秉县| 南城县| 旬阳县|