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)。
#includeusing 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ā)生偏移等。于是,當我們構(gòu)建具體的類時,若是基類類型,__vptr就會指向父類的vtable,若是子類類型,__vptr就會指向子類的vtable。
下面再看一個實例來了解虛函數(shù)表,及對象的函數(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; }; // 通過訪問類對象的前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ù)在編譯器進行推導,以確定哪一個函數(shù)被調(diào)用。
3.1 運行期多態(tài)優(yōu)點
OO設(shè)計中重要的特性,對客觀世界直覺認識。
能夠處理同一個繼承體系下的異質(zhì)類集合。
3.2 運行期多態(tài)缺點
運行期間進行虛函數(shù)綁定,提高了程序運行開銷。
龐大的類繼承層次,對接口的修改易影響類繼承層次。
由于虛函數(shù)在運行期在確定,所以編譯器無法對虛函數(shù)進行優(yōu)化。
虛表指針增大了對象體積,類也多了一張?zhí)摵瘮?shù)表,當然,這是理所應(yīng)當值得付出的資源消耗,列為缺點有點勉強。
3.3 編譯期多態(tài)優(yōu)點
它帶來了泛型編程的概念,使得C++擁有泛型編程與STL這樣的強大武器。
在編譯器完成多態(tài),提高運行期效率。
具有很強的適配性與松耦合性,對于特殊類型可由模板偏特化、全特化來處理。
3.4 編譯期多態(tài)缺點
程序可讀性降低,代碼調(diào)試帶來困難。
無法實現(xiàn)模板的分離編譯,當工程很大時,編譯時間不可小覷。
無法處理異質(zhì)對象集合。
新聞標題:C++運行期多態(tài)和編譯期多態(tài)(以不同的模板參數(shù)調(diào)用不同的函數(shù))
瀏覽路徑:http://www.rwnh.cn/news/99414.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google、域名注冊、自適應(yīng)網(wǎng)站、定制網(wǎng)站、面包屑導航、手機網(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)
猜你還喜歡下面的內(nèi)容