2021-02-06 分類: 網(wǎng)站建設(shè)
在面向?qū)ο驝++編程中,多態(tài)是OO三大特性之一,這種多態(tài)稱為運(yùn)行期多態(tài),也稱為動(dòng)態(tài)多態(tài);在泛型編程中,多態(tài)基于template(模板)的具現(xiàn)化與函數(shù)的重載解析,這種多態(tài)在編譯期進(jìn)行,因此稱為編譯期多態(tài)或靜態(tài)多態(tài)。
該類對(duì)象安插一個(gè)虛函數(shù)表指針,并為類(基類和派生類)設(shè)置虛函數(shù)表,虛函數(shù)表中存放的是該類虛函數(shù)地址。同時(shí),改寫虛函數(shù)調(diào)用代碼(函數(shù)指針調(diào)用)。運(yùn)行期間通過虛函數(shù)表指針與虛函數(shù)表去確定該類虛函數(shù)的真正實(shí)現(xiàn)。
#includeusing namespace std; class Animal { public :virtual void shout() = 0; }; class Dog :public Animal { public:virtual void shout(){ cout <><< "汪汪!"<shout();//虛函數(shù)的調(diào)用會(huì)被編譯器轉(zhuǎn)換為對(duì)虛函數(shù)表的訪問Cat cat;// ② 編譯器會(huì)為每個(gè)新建對(duì)象添加一函數(shù)指針,指向虛函數(shù)表animal = &cat;animal->shout();//animal代表this指針,shout是虛函數(shù)// ③ 編譯器會(huì)改寫對(duì)象調(diào)用成員函數(shù)代碼,改寫成指針調(diào)用的形式Animal * anim3 = new Bird;anim3->shout();delete anim3;system("pause");return 0; } /* 汪汪! 喵喵~ 嘰喳! */
編譯器會(huì)構(gòu)建一張?zhí)摫恚?vtable ),每一個(gè)類都有自己獨(dú)特的虛表。同時(shí),在這個(gè)繼承鏈上,編譯器會(huì)為基類插入一個(gè)隱式的指針(一般是對(duì)象的首地址),指向虛表,稱為__vptr。然后,子類繼承父類時(shí),會(huì)獲得繼承下來的__vptr,再根據(jù)自己的類的情況兼容(修改虛函數(shù)表里的值、發(fā)生偏移等。于是,當(dāng)我們構(gòu)建具體的類時(shí),若是基類類型,__vptr就會(huì)指向父類的vtable,若是子類類型,__vptr就會(huì)指向子類的vtable。
下面再看一個(gè)實(shí)例來了解虛函數(shù)表,及對(duì)象的函數(shù)指針是如何指向虛函數(shù)表以及調(diào)用虛函數(shù)代碼是如何改寫的?
#includeusing 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; }; // 通過訪問類對(duì)象的前4字節(jié)(32位編譯器)找到虛函數(shù)表。 // 虛函數(shù)表最后一項(xiàng)用的是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ù)在編譯器進(jìn)行推導(dǎo),以確定哪一個(gè)函數(shù)被調(diào)用。
3.1 運(yùn)行期多態(tài)優(yōu)點(diǎn)
OO設(shè)計(jì)中重要的特性,對(duì)客觀世界直覺認(rèn)識(shí)。
能夠處理同一個(gè)繼承體系下的異質(zhì)類集合。
3.2 運(yùn)行期多態(tài)缺點(diǎn)
運(yùn)行期間進(jìn)行虛函數(shù)綁定,提高了程序運(yùn)行開銷。
龐大的類繼承層次,對(duì)接口的修改易影響類繼承層次。
由于虛函數(shù)在運(yùn)行期在確定,所以編譯器無法對(duì)虛函數(shù)進(jìn)行優(yōu)化。
虛表指針增大了對(duì)象體積,類也多了一張?zhí)摵瘮?shù)表,當(dāng)然,這是理所應(yīng)當(dāng)值得付出的資源消耗,列為缺點(diǎn)有點(diǎn)勉強(qiáng)。
3.3 編譯期多態(tài)優(yōu)點(diǎn)
它帶來了泛型編程的概念,使得C++擁有泛型編程與STL這樣的強(qiáng)大武器。
在編譯器完成多態(tài),提高運(yùn)行期效率。
具有很強(qiáng)的適配性與松耦合性,對(duì)于特殊類型可由模板偏特化、全特化來處理。
3.4 編譯期多態(tài)缺點(diǎn)
程序可讀性降低,代碼調(diào)試帶來困難。
無法實(shí)現(xiàn)模板的分離編譯,當(dāng)工程很大時(shí),編譯時(shí)間不可小覷。
無法處理異質(zhì)對(duì)象集合。
文章標(biāo)題:C++運(yùn)行期多態(tài)和編譯期多態(tài)(以不同的模板參數(shù)調(diào)用不同的函數(shù))
當(dāng)前地址:http://jinyejixie.com/news14/99414.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊(cè)、微信公眾號(hào)、ChatGPT、搜索引擎優(yōu)化、品牌網(wǎng)站建設(shè)、微信小程序
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容