C++運行期多態(tài)和編譯期多態(tài)(以不同的模板參數(shù)調(diào)用不同的函數(shù))

2021-02-06    分類: 網(wǎng)站建設(shè)

在面向?qū)ο驝++編程中,多態(tài)是OO三大特性之一,這種多態(tài)稱為運行期多態(tài),也稱為動態(tài)多態(tài);在泛型編程中,多態(tài)基于template(模板)的具現(xiàn)化與函數(shù)的重載解析,這種多態(tài)在編譯期進行,因此稱為編譯期多態(tài)或靜態(tài)多態(tài)。

該類對象安插一個虛函數(shù)表指針,并為類(基類和派生類)設(shè)置虛函數(shù)表,虛函數(shù)表中存放的是該類虛函數(shù)地址。同時,改寫虛函數(shù)調(diào)用代碼(函數(shù)指針調(diào)用)。運行期間通過虛函數(shù)表指針與虛函數(shù)表去確定該類虛函數(shù)的真正實現(xiàn)。

#include
using namespace std;
class Animal
{
public :virtual void shout() = 0;
};
class Dog :public Animal
{
public:virtual void shout(){ cout << "汪汪!"<shout();//虛函數(shù)的調(diào)用會被編譯器轉(zhuǎn)換為對虛函數(shù)表的訪問Cat cat;// ② 編譯器會為每個新建對象添加一函數(shù)指針,指向虛函數(shù)表animal = &cat;animal->shout();//animal代表this指針,shout是虛函數(shù)// ③ 編譯器會改寫對象調(diào)用成員函數(shù)代碼,改寫成指針調(diào)用的形式Animal * anim3 = new Bird;anim3->shout();delete anim3;system("pause");return 0;
}
/*
汪汪!
喵喵~
嘰喳!
*/

編譯器會構(gòu)建一張?zhí)摫恚?vtable ),每一個類都有自己獨特的虛表。同時,在這個繼承鏈上,編譯器會為基類插入一個隱式的指針(一般是對象的首地址),指向虛表,稱為__vptr。然后,子類繼承父類時,會獲得繼承下來的__vptr,再根據(jù)自己的類的情況兼容(修改虛函數(shù)表里的值、發(fā)生偏移等。于是,當(dāng)我們構(gòu)建具體的類時,若是基類類型,__vptr就會指向父類的vtable,若是子類類型,__vptr就會指向子類的vtable。


下面再看一個實例來了解虛函數(shù)表,及對象的函數(shù)指針是如何指向虛函數(shù)表以及調(diào)用虛函數(shù)代碼是如何改寫的?

#include 
using namespace std;
class A
{
public:
 A(int _a1 = 1) : a1(_a1) { }
 virtual void f() { cout << "A::f" << endl; }
 virtual void g() { cout << "A::g" << endl; }
 virtual void h() { cout << "A::h" << endl; }
 ~A() {}
private:
 int a1;
};
class C : public A
{
public:
 C(int _a1 = 1, int _c = 4) :A(_a1), c(_c) { }
 virtual void f() { cout << "C::f" << endl; }
 virtual void g() { cout << "C::g" << endl; }
 virtual void h() { cout << "C::h" << endl; }
private:
 int c;
};
// 通過訪問類對象的前4字節(jié)(32位編譯器)找到虛函數(shù)表。
// 虛函數(shù)表最后一項用的是0,代表虛函數(shù)表結(jié)束。
typedef void(*FUNC)(); //重定義函數(shù)指針,指向函數(shù)的指針
void PrintVTable(long* vTable) //訪問虛函數(shù)表
{
 if (vTable == NULL)
 {
 return;
 }
 cout << "vtbl:" << vTable << endl;
 int i = 0;
 for (; vTable[i] != 0; ++i)
 {
 printf("function : %d :0X%x->", i, vTable[i]);
 FUNC f = (FUNC)vTable[i];
 f(); //訪問虛函數(shù)
 }
 cout << endl;
}
void main()
{A a1;long *p = (long *)(*(long*)&a1);PrintVTable(p);C c;long *p2 = (long *)(*(long*)&c);PrintVTable(p2);system("pause");
}
/*
vtbl:00471048
function : 0 :0X40105a->A::f
function : 1 :0X4012c6->A::g
function : 2 :0X4010b9->A::h
vtbl:00471070
function : 0 :0X4010eb->C::f
function : 1 :0X4011d1->C::g
function : 2 :0X401280->C::h
*/

不同的推斷結(jié)果調(diào)用不同的函數(shù),這就是編譯器多態(tài)。這類似于重載函數(shù)在編譯器進行推導(dǎo),以確定哪一個函數(shù)被調(diào)用。

3 運行期多態(tài)與編譯期多態(tài)優(yōu)缺點分析

3.1 運行期多態(tài)優(yōu)點

OO設(shè)計中重要的特性,對客觀世界直覺認(rèn)識。

能夠處理同一個繼承體系下的異質(zhì)類集合。

3.2 運行期多態(tài)缺點

運行期間進行虛函數(shù)綁定,提高了程序運行開銷。

龐大的類繼承層次,對接口的修改易影響類繼承層次。

由于虛函數(shù)在運行期在確定,所以編譯器無法對虛函數(shù)進行優(yōu)化。

虛表指針增大了對象體積,類也多了一張?zhí)摵瘮?shù)表,當(dāng)然,這是理所應(yīng)當(dāng)值得付出的資源消耗,列為缺點有點勉強。

3.3 編譯期多態(tài)優(yōu)點

它帶來了泛型編程的概念,使得C++擁有泛型編程與STL這樣的強大武器。

在編譯器完成多態(tài),提高運行期效率。

具有很強的適配性與松耦合性,對于特殊類型可由模板偏特化、全特化來處理。

3.4 編譯期多態(tài)缺點

程序可讀性降低,代碼調(diào)試帶來困難。

無法實現(xiàn)模板的分離編譯,當(dāng)工程很大時,編譯時間不可小覷。

無法處理異質(zhì)對象集合。

文章標(biāo)題:C++運行期多態(tài)和編譯期多態(tài)(以不同的模板參數(shù)調(diào)用不同的函數(shù))
當(dāng)前地址:http://www.bm7419.com/news14/99414.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊、微信公眾號ChatGPT、搜索引擎優(yōu)化品牌網(wǎng)站建設(shè)、微信小程序

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)