国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表)

這篇具有很好參考價值的文章主要介紹了C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

一:多態(tài)的原理?

1.虛函數(shù)表

?2.原理分析

3.對于虛表存在哪里的探討

4.對于是不是所有的虛函數(shù)都要存進虛函數(shù)表的探討

二:多繼承中的虛函數(shù)表

三:常見的問答題?

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

接下來的日子會順順利利,萬事勝意,生活明朗-----------林辭憂?

接上篇的多態(tài)的介紹后,接下來介紹多態(tài)的原理以及虛函數(shù)表的相關(guān)知識

一:多態(tài)的原理?

1.虛函數(shù)表

這里從一道經(jīng)典筆試題引入

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

對于這道題我們可能想到的是計算類 大小的對齊規(guī)則,結(jié)果為4,但結(jié)果為8,這是因為有虛函數(shù)的類要多考慮一指針

在32位系統(tǒng)下是8

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

如果這里再添加幾個虛函數(shù)呢?

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++?

所以在這里不管類里面有多少個虛函數(shù) ,只要是包含虛函數(shù)的類計算大小都要考慮添加一指針,再考慮對齊

但這里的一指針是什么呢?

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

但這里我們就看到在b1中除了_b還存有 一個_vfptr的指針在對象的前面,這個指針就叫做虛函數(shù)表指針,其中v代表virtual,f代表funcation

每一個含有虛函數(shù)的類都至少有一個虛函數(shù)表指針,他的類型為函數(shù)指針數(shù)組,而虛函數(shù)的地址是存放在虛函數(shù)表中的,虛函數(shù)表也叫虛表

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

?2.原理分析

class Base
{
public:
	virtual void Func1()
    {
		cout << "Func1()" << endl;
    }
	virtual void Func2()
	{
		cout << "Func2()" << endl;
	}
	
private:
	int _b = 1;
};
class Derived : public Base
{
	virtual void Func1()
	{
		cout << "Func()" << endl;
	}
private:
	int _a = 0;
};

int main()
{
	Base b1;
	Derived d1;
	return 0;
}

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++?

解釋多態(tài)調(diào)用的兩個條件

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

對于條件一:必須是父類的指針或引用來調(diào)用函數(shù)

1.父類的指針指向父類對象時,依據(jù)虛函數(shù)表指針(vfptr),在虛函數(shù)表中找到函數(shù)的地址,再call這個地址來執(zhí)行接下來的操作

2.父類的指針指向子類對象時,先完成切片,找到父類的那一部分,依據(jù)虛函數(shù)表指針(vfptr),在虛函數(shù)表中找到函數(shù)的地址,再call這個地址來執(zhí)行接下來的操作

3.由于經(jīng)過虛函數(shù)的重寫后,虛函數(shù)的地址是不相同的,所以結(jié)果是不相同的,這是就形成了多態(tài)

對于編譯器來說上面的兩個調(diào)用是執(zhí)行的同樣的操作,都只是取對象的頭四個字節(jié),就是虛函數(shù)表指針,然后去虛表中找到對應(yīng)調(diào)用函數(shù)的地址,然后執(zhí)行接下來的操作

4.如果是父類的對象調(diào)用函數(shù)的話這時就要分析可能會總成的結(jié)果

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

這時尤其是這樣的場景,Person* ptr=new Person,Student s;? ?*ptr=s?,這樣如果支持能拷貝虛函數(shù)表指針的話,這時delete? ptr,就調(diào)用的是 Student類的析構(gòu)函數(shù),導(dǎo)致直接錯誤的

5.對于多態(tài)調(diào)用是在運行時,去虛表里面找到函數(shù)指針,確定函數(shù)指針后,調(diào)用函數(shù);

對于普通調(diào)用是在編譯鏈接時,確定函數(shù)地址

6.派生類中只有一個虛表指針(菱形繼承除外),同一個類的對象共用一張?zhí)摫?/span>

7.虛函數(shù)也是也是和成員函數(shù)一樣存在代碼段的,不同的是虛函數(shù)會將自己的地址存在虛表中

對于條件二:虛函數(shù)的重寫

從上面就可以看出虛函數(shù)的重寫也叫覆蓋,覆蓋了原先虛函數(shù)的地址,重寫是語法層的叫法,而覆蓋是原理層的叫法

三:派生類的虛表生成

1.先將基類中的虛表內(nèi)容拷貝一份到派生類的虛表中

2.如果派生類重寫了基類中的某個虛函數(shù),用派生類自己的虛函數(shù)的地址來覆蓋虛表中基類的虛函數(shù)地址

3.派生類自己新增的虛函數(shù)按其在派生類中的聲明順序增加到派生類虛表的最后

3.對于虛表存在哪里的探討

對于棧和堆是不可能的,只有代碼段或者靜態(tài)區(qū),但我們可以自己驗證是存在哪里的

驗證代碼

class Base {
public:
	virtual void func1() { cout << "Base::func1" << endl; }
	virtual void func2() { cout << "Base::func2" << endl; }
private:
	int a;
};
void func()
{
	cout << "void func()" << endl;
}
int main()
{
	Base b1;
	Base b2;

	static int a = 0;
	int b = 0;
	int* p1 = new int;
	const char* p2 = "hello world";
	printf("靜態(tài)區(qū):%p\n", &a);
	printf("棧:%p\n", &b);
	printf("堆:%p\n", p1);
	printf("代碼段:%p\n", p2);
	printf("虛表:%p\n", *((int*)&b1));
	printf("虛函數(shù)地址:%p\n", &Base::func1);
	printf("普通函數(shù)地址:%p\n", func);

	return 0;
}

對于這里的取虛表地址

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++?

可以這樣來理解,&b1是整個類的地址,然后強轉(zhuǎn)為(int*),再解引用取得就是頭四個字節(jié),即虛表地址?

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++?

我們發(fā)現(xiàn) 和虛表地址最接近的為代碼段的地址,所以可以確定虛表是存在代碼段的

4.對于是不是所有的虛函數(shù)都要存進虛函數(shù)表的探討

首先確定答案 一定都是存在虛函數(shù)表的

接下來我們在vs上監(jiān)視窗口來查看

分析代碼

class Base {
public:
	virtual void func1() { cout << "Base::func1" << endl; }
	virtual void func2() { cout << "Base::func2" << endl; }
private:
	int a;
};

class Derive :public Base {
public:
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func3() { cout << "Derive::func3" << endl; }
	virtual void func4() { cout << "Derive::func4" << endl; }
	void func5() { cout << "Derive::func5" << endl; }
private:
	int b;
};

class X :public Derive {
public:
	virtual void func3() { cout << "X::func3" << endl; }
};

int main()
{
	Base b;
	Derive d;
	X x;

	Derive* p = &d;
	p->func3();

	p = &x;
	p->func3();

	return 0;
}

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++??

對于這里監(jiān)視窗口的顯示,在這里對于b是只有兩個虛函數(shù)都存進了虛函數(shù)表中,但對于d和x都應(yīng)該是四個虛函數(shù)存進虛函數(shù)表的,但在這里都只存了兩個虛函數(shù),但驗證多態(tài)調(diào)用的話,結(jié)果為

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

結(jié)果是多態(tài)調(diào)用,?這時我們就不得不質(zhì)疑此時監(jiān)視窗口 的結(jié)果了

為了進一步的證明。我們可以調(diào)用內(nèi)存窗口來查看

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

在內(nèi)存中我們就會發(fā)現(xiàn)后兩個地址與前兩個虛函數(shù)的地址很接近,所以我們暫時可以認為虛函數(shù)是都存在虛函數(shù)表中的,

為了確定結(jié)果,我們可以使用打印虛表來驗證猜想

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

class Base {
public:
	virtual void func1() { cout << "Base::func1" << endl; }
	virtual void func2() { cout << "Base::func2" << endl; }
private:
	int a;
};

class Derive :public Base {
public:
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func3() { cout << "Derive::func3" << endl; }
	virtual void func4() { cout << "Derive::func4" << endl; }
	void func5() { cout << "Derive::func5" << endl; }
private:
	int b;
};

class X :public Derive {
public:
	virtual void func3() { cout << "X::func3" << endl; }
};

typedef void (*VFUNC)();
//void PrintVFT(VFUNC a[])
void PrintVFT(VFUNC* a)
{
	for (size_t i = 0; a[i] != 0; i++)
	{
		printf("[%d]:%p->", i, a[i]);
		VFUNC f = a[i];
		f();
		//(*f)();
	}
	printf("\n");
}

int main()
{
	Base b;
	PrintVFT((VFUNC*)(*((long long*)&b)));//32位的話,可以采用int

	Derive d;
	X x;

	// PrintVFT((VFUNC*)&d);
	PrintVFT((VFUNC*)(*((long long*)&d)));

	PrintVFT((VFUNC*)(*((long long*)&x)));

	return 0;
}

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++?

這樣看,只要是虛函數(shù),都會將地址存到類的虛函數(shù)表里面的

?文章來源地址http://www.zghlxwxcb.cn/news/detail-858471.html

二:多繼承中的虛函數(shù)表

同樣的我們可以采用例子來介紹

class Base1 {
public:
	virtual void func1() { cout << "Base1::func1" << endl; }
	virtual void func2() { cout << "Base1::func2" << endl; }
private:
	int b1;
};

class Base2 {
public:
	virtual void func1() { cout << "Base2::func1" << endl; }
	virtual void func2() { cout << "Base2::func2" << endl; }
private:
	int b2;
};

class Derive : public Base1, public Base2 {
public:
	virtual void func1() 
	{ 
		cout << "Derive::func1" << endl;
	}

	virtual void func3() { cout << "Derive::func3" << endl; }
private:
	int d1;
};

int main()
{
	Derive d;

	Base1* p1 = &d;
	p1->func1();

	Base2* p2 = &d;
	p2->func1();

	return 0;
}

采用監(jiān)視窗口的話?

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

就會發(fā)現(xiàn)對于基類的兩張?zhí)摫碇卸紱]有存derived類的fun3() ,但我們可以使用多態(tài)的調(diào)用來驗證下

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

所以的話,fun3是一定存在基類的兩張?虛表中的其中一個里面,這樣采用內(nèi)存來看

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

所以最好的方式,我們還是來打印兩個基類的虛函數(shù)表的?

typedef void (*VFUNC)();
//void PrintVFT(VFUNC a[])
void PrintVFT(VFUNC* a)
{
	for (size_t i = 0; a[i] != 0; i++)
	{
		printf("[%d]:%p->", i, a[i]);
		VFUNC f = a[i];
		f();
		//(*f)();
	}
	printf("\n");
}
class Base1 {
public:
	virtual void func1() { cout << "Base1::func1" << endl; }
	virtual void func2() { cout << "Base1::func2" << endl; }
private:
	int b1;
};

class Base2 {
public:
	virtual void func1() { cout << "Base2::func1" << endl; }
	virtual void func2() { cout << "Base2::func2" << endl; }
private:
	int b2;
};

class Derive : public Base1, public Base2 {
public:
	virtual void func1() 
	{ 
		cout << "Derive::func1" << endl;
	}

	virtual void func3() { cout << "Derive::func3" << endl; }
private:
	int d1;
};

int main()
{
	Derive d;
     PrintVFT((VFUNC*)(*(int*)&d));

     //PrintVFT((VFUNC*)(*(int*)((char*)&d+sizeof(Base1))));
     Base2* ptr = &d;
     PrintVFT((VFUNC*)(*(int*)ptr));

	
	/*Base1* p1 = &d;
	p1->func1();

	Base2* p2 = &d;
	p2->func1();*/

	return 0;
}

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++?

所以此時我們就會知道,派生類的虛函數(shù)地址是存在第一個基類的虛函數(shù)表里面的?

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

三:常見的問答題?

C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表),c++,c++

?

到了這里,關(guān)于C++修煉之路之多態(tài)---多態(tài)的原理(虛函數(shù)表)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 【C++】虛函數(shù)表 & 多態(tài)的原理 & 動態(tài)綁定和靜態(tài)綁定

    【C++】虛函數(shù)表 & 多態(tài)的原理 & 動態(tài)綁定和靜態(tài)綁定

    梳理虛函數(shù)表、多態(tài)原理、動靜態(tài)綁定的知識 目錄 一、虛函數(shù)表 二、多態(tài)的原理 三、動態(tài)綁定和靜態(tài)綁定 在學(xué)習(xí)多態(tài)原理之前,我們需要了解一下虛函數(shù)表的概念? 我們先一起來看下下面這段代碼 通過測試我們發(fā)現(xiàn)b對象是8bytes, 除了_b成員,還多一個__vfptr指針放在對象

    2024年02月03日
    瀏覽(28)
  • 【C++修煉之路】C++入門(上)

    【C++修煉之路】C++入門(上)

    ??作者主頁:@安 度 因 ??學(xué)習(xí)社區(qū):安度因的學(xué)習(xí)社區(qū) ??專欄鏈接:C++修煉之路

    2024年01月17日
    瀏覽(18)
  • 【C++修煉之路】內(nèi)存管理

    【C++修煉之路】內(nèi)存管理

    ??作者主頁:@安 度 因 ??學(xué)習(xí)社區(qū):StackFrame ??專欄鏈接:C++修煉之路

    2024年02月16日
    瀏覽(23)
  • C++類和對象-多態(tài)->多態(tài)的基本語法、多態(tài)的原理剖析、純虛函數(shù)和抽象類、虛析構(gòu)和純虛析構(gòu)

    C++類和對象-多態(tài)->多態(tài)的基本語法、多態(tài)的原理剖析、純虛函數(shù)和抽象類、虛析構(gòu)和純虛析構(gòu)

    #includeiostream using namespace std; //多態(tài) //動物類 class Animal { public: ?? ?//Speak函數(shù)就是虛函數(shù) ?? ?//函數(shù)前面加上virtual,變成虛函數(shù),那么編譯器在編譯的時候就不能確定函數(shù)調(diào)用了。 ?? ?virtual void speak() ?? ?{ ?? ??? ?cout \\\"動物在說話\\\" endl; ?? ?} }; //貓類 class Cat

    2024年02月20日
    瀏覽(23)
  • 【C++修煉之路】list 模擬實現(xiàn)

    【C++修煉之路】list 模擬實現(xiàn)

    ??作者主頁:@安 度 因 ??學(xué)習(xí)社區(qū):StackFrame ??專欄鏈接:C++修煉之路

    2024年02月16日
    瀏覽(15)
  • 【C++修煉之路】33.特殊類設(shè)計

    【C++修煉之路】33.特殊類設(shè)計

    每一個不曾起舞的日子都是對生命的辜負 掌握常見特殊類的設(shè)計方式 拷貝只會放生在兩個場景中:拷貝構(gòu)造函數(shù)以及賦值運算符重載,因此想要讓一個類禁止拷貝,只需讓該類不能調(diào)用拷貝構(gòu)造函數(shù)以及賦值運算符重載即可。 C++98 將拷貝構(gòu)造函數(shù)與賦值運算符重載只聲明不

    2024年02月13日
    瀏覽(16)
  • 【C++庖丁解?!棵嫦?qū)ο蟮娜筇匦灾欢鄳B(tài) | 抽象類 | 多態(tài)的原理 | 單繼承和多繼承關(guān)系中的虛函數(shù)表

    【C++庖丁解牛】面向?qū)ο蟮娜筇匦灾欢鄳B(tài) | 抽象類 | 多態(tài)的原理 | 單繼承和多繼承關(guān)系中的虛函數(shù)表

    ??你好,我是 RO-BERRY ?? 致力于C、C++、數(shù)據(jù)結(jié)構(gòu)、TCP/IP、數(shù)據(jù)庫等等一系列知識 ??感謝你的陪伴與支持 ,故事既有了開頭,就要畫上一個完美的句號,讓我們一起加油 需要聲明的,本節(jié)課件中的代碼及解釋都是在vs2013下的x86程序中,涉及的指針都是4bytes。如果要其他平臺

    2024年04月10日
    瀏覽(28)
  • 【C++進階之路】多態(tài)篇

    【C++進階之路】多態(tài)篇

    ?多態(tài),顧名思義,就是 一件事物具備不同的形態(tài) ,是繼承之后, 面向?qū)ο蟮牡谌筇匦?,可以這樣說: 有了繼承才有了類的多態(tài),而類的多態(tài)是為了更好的實現(xiàn)繼承。 ?多態(tài)的列車即將起航,不知你準備好了嗎? ? 繼承與多態(tài)相輔相成 。 舉個例子: ?我們都是人(

    2024年02月15日
    瀏覽(20)
  • c++的學(xué)習(xí)之路:22、多態(tài)(1)

    c++的學(xué)習(xí)之路:22、多態(tài)(1)

    本章主要是說一些多態(tài)的開頭。 目錄 摘要 一、多態(tài)的概念 二、多態(tài)的定義及實現(xiàn) 2.1、多態(tài)的構(gòu)成條件 2.2、虛函數(shù) 2.3、虛函數(shù)的重寫 2.4、C++11 override 和 ?nal? 2.5、重載、覆蓋(重寫)、隱藏(重定義)的對比 三、思維導(dǎo)圖 多態(tài)的概念:通俗來說,就是多種形態(tài),具體點就是去

    2024年04月14日
    瀏覽(20)
  • 【C++程序員的自我修煉】拷貝構(gòu)造函數(shù)

    【C++程序員的自我修煉】拷貝構(gòu)造函數(shù)

    心存希冀 追光而遇目有繁星 沐光而行 目錄 拷貝構(gòu)造函數(shù)概念 拷貝構(gòu)造的特征 無窮遞歸的解釋 淺拷貝 總結(jié): ?深拷貝 拷貝構(gòu)造函數(shù)典型調(diào)用場景 總結(jié)? 契子 ? 在生活中總有很多瑣事,不做不行做了又怕麻煩,有時候想要是有個和自己一模一樣的人就好了 可以幫我上早讀

    2024年04月14日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包