0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀(guān)看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

探討C++多態(tài)性技術(shù)的局限性及解決的辦法

C語(yǔ)言專(zhuān)家集中營(yíng) ? 2018-01-08 11:06 ? 次閱讀

多態(tài)性是指發(fā)出同樣的消息被不同類(lèi)型的對(duì)象接收時(shí)有可能導(dǎo)致完全不同的行為。利用多態(tài)性技術(shù),可以調(diào)用同一個(gè)函數(shù)名的函數(shù),實(shí)現(xiàn)完全不同的功能。C++多態(tài)性是通過(guò)虛函數(shù)來(lái)實(shí)現(xiàn)的。下面讓我們一同跟隨作者進(jìn)一步了解多態(tài)的含義。

面向?qū)ο蠹夹g(shù)最早出現(xiàn)于1960年代的Simula 67系統(tǒng),并且在1970年代保羅阿托實(shí)驗(yàn)室開(kāi)發(fā)的Smalltalk系統(tǒng)中發(fā)展成熟。然而對(duì)于大部分程序員來(lái)說(shuō),C++是第一個(gè)可用的面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言。因此,我們關(guān)于面向?qū)ο蟮暮芏喔拍詈退枷胫苯觼?lái)自于C++。但是,C++在實(shí)現(xiàn)面向?qū)ο笾嘘P(guān)鍵的多態(tài)性時(shí),選擇了與Smalltalk完全不同的方案。其結(jié)果是,盡管在表面上兩者都實(shí)現(xiàn)了相似的多態(tài)性,但是在實(shí)踐中卻有著巨大的區(qū)別。具體的說(shuō),C++的多態(tài)性實(shí)現(xiàn)更加高效,但是并不適用于所有場(chǎng)合。很多經(jīng)驗(yàn)不足的C++開(kāi)發(fā)者不明白這個(gè)道理,在不合適的場(chǎng)合強(qiáng)行使用C++的多態(tài)性機(jī)制,落入削足適履的陷阱而不能自拔。本文將詳細(xì)探討C++多態(tài)性技術(shù)的局限性及解決的辦法。

兩種不同虛方法調(diào)用實(shí)現(xiàn)技術(shù)

C++的多態(tài)性是C++實(shí)現(xiàn)面向?qū)ο蠹夹g(shù)的基礎(chǔ)。具體的說(shuō),通過(guò)一個(gè)指向基類(lèi)的指針調(diào)用虛成員函數(shù)的時(shí)候,運(yùn)行時(shí)系統(tǒng)將能夠根據(jù)指針?biāo)赶虻膶?shí)際對(duì)象調(diào)用恰當(dāng)?shù)某蓡T函數(shù)實(shí)現(xiàn)。如下所示:

classBase{

public:

virtualvoidvmf(){...}

};

classDerived:publicBase{

public:

virtualvoidvmf(){...}

};

Base*p=newBase();

p->vmf();//這里調(diào)用Base::vmf

p=newDerived();

p->vmf();//這里調(diào)用

//Derived::vmf

...

請(qǐng)注意代碼中突出注釋的兩行,雖然其表面語(yǔ)法完全相同,但是卻分別調(diào)用了不同的函數(shù)實(shí)現(xiàn)。所謂的“多態(tài)”即就此而言。這些知識(shí)是每一個(gè)C++開(kāi)發(fā)者都熟知的。

現(xiàn)在我們假設(shè)自己是語(yǔ)言的實(shí)現(xiàn)者,我們應(yīng)當(dāng)如何來(lái)實(shí)現(xiàn)這種多態(tài)性?稍加思考,我們不難得到一個(gè)基本的思路。多態(tài)性的實(shí)現(xiàn)要求我們?cè)黾右粋€(gè)間接層,在這個(gè)間接層中攔截對(duì)于方法的調(diào)用,然后根據(jù)指針?biāo)赶虻膶?shí)際對(duì)象調(diào)用相應(yīng)的方法實(shí)現(xiàn)。在這個(gè)過(guò)程中我們?nèi)藶樵黾拥倪@個(gè)間接層非常重要,它需要完成以下幾項(xiàng)工作:

1. 獲知方法調(diào)用的全部信息,包括被調(diào)用的是哪個(gè)方法,傳入的實(shí)際參數(shù)有哪些。

2. 獲知調(diào)用發(fā)生時(shí)指針(引用)所指向的實(shí)際對(duì)象。

3. 根據(jù)第1、2步獲得的信息,找到合適的方法實(shí)現(xiàn)代碼,執(zhí)行調(diào)用。

這里的關(guān)鍵在于如何在第3 步中找到合適的方法實(shí)現(xiàn)代碼。由于多態(tài)性是就對(duì)象而言的,因此我們?cè)谠O(shè)計(jì)時(shí)要把合適的方法實(shí)現(xiàn)代碼與對(duì)象綁定到一起。也就是說(shuō),必須在對(duì)象級(jí)別實(shí)現(xiàn)一個(gè)查找表結(jié)構(gòu),根據(jù)1、2步獲得的對(duì)象和方法信息,在這個(gè)查找表中找到實(shí)際的方法代碼地址,并加以調(diào)用?,F(xiàn)在問(wèn)題變成了,我們應(yīng)當(dāng)根據(jù)什么信息進(jìn)行方法查找。對(duì)于這個(gè)問(wèn)題有兩個(gè)不同的解決思路,一個(gè)是根據(jù)名稱(chēng)進(jìn)行查找,另一個(gè)是根據(jù)位置進(jìn)行查找。粗看上去這兩種思路似乎沒(méi)什么大的差別,但是在實(shí)踐中,這兩種不同的實(shí)現(xiàn)思路導(dǎo)致了巨大的差別。下面我們?cè)敿?xì)地加以考察。

在Smalltalk、Python、Ruby等動(dòng)態(tài)面向?qū)ο笳Z(yǔ)言中,實(shí)際方法的查找是根據(jù)方法名稱(chēng)進(jìn)行的,其查找表結(jié)構(gòu)如下:

由于這種查找表根據(jù)方法的名稱(chēng)進(jìn)行方法查找,因此在查找過(guò)程中涉及字符串比較,效率較差。但是這種查找表有一個(gè)突出的優(yōu)點(diǎn),就是有效空間利用率高。為了說(shuō)明這一點(diǎn),我們假設(shè)一個(gè)基類(lèi)Base中有100個(gè)方法可供派生類(lèi)改寫(xiě)(因此所有Base對(duì)象所共享的方法查找表有100項(xiàng)),而它的一個(gè)派生類(lèi)Derived僅僅只打算改寫(xiě)其中5個(gè)方法,那么Derived類(lèi)對(duì)象的方法查找表只需要5項(xiàng)。當(dāng)一個(gè)方法調(diào)用發(fā)生的時(shí)候,runtime根據(jù)被調(diào)用的方法名稱(chēng)在這個(gè)長(zhǎng)度為5 的方法查找表中進(jìn)行字符串查找,如果發(fā)現(xiàn)該方法在查找表中,則執(zhí)行調(diào)用,否則將調(diào)用轉(zhuǎn)寄(forward)給Base類(lèi)執(zhí)行。這是虛方法調(diào)用的標(biāo)準(zhǔn)行為。當(dāng)派生類(lèi)實(shí)際改寫(xiě)的方法數(shù)量很少的時(shí)候,可以將查找表安排成線(xiàn)性表,查找時(shí)順序比較,這種情況下有效空間利用率達(dá)到100%。如果派生類(lèi)實(shí)際改寫(xiě)的方法數(shù)量較多,那么可以采用散列表,如果采用合理的散列函數(shù),同樣可以在空間利用率很高(一般可接近75%).. 的情況下實(shí)現(xiàn)方法的快速查找。應(yīng)當(dāng)注意到,由于編譯器可以很容易地獲得所有被改寫(xiě)方法的名稱(chēng),因此可以執(zhí)行標(biāo)準(zhǔn)的gperf算法獲得最優(yōu)的散列函數(shù)。

事實(shí)上,我們還可以這樣理解這種方案的優(yōu)勢(shì),把表中每一項(xiàng)的“方法名”項(xiàng)視為“方法地址”項(xiàng)的描述信息,因此可以認(rèn)為這種方案中的方法查找表攜帶自描述信息(或者稱(chēng)為元數(shù)據(jù))?;谶@種攜帶自描述信息的數(shù)據(jù)結(jié)構(gòu),可以實(shí)現(xiàn)豐富多彩的擴(kuò)展功能,比如在運(yùn)行時(shí)插入新的方法,或者用戶(hù)層次上的方法調(diào)用截獲等。因此,我們可以說(shuō)這一方案的適用面廣,強(qiáng)大靈活,但在執(zhí)行效率上并非最優(yōu)。

另一種虛方法查找方案則是C++ 開(kāi)發(fā)者十分熟悉的,基于絕對(duì)位置的定位技術(shù)。其查找表結(jié)構(gòu)非常簡(jiǎn)單,僅僅是一個(gè)存放了方法地址的指針數(shù)組。表中的每一項(xiàng)不具有自描述性,只有編譯器在編譯時(shí)知道它們究竟分別對(duì)應(yīng)著哪一個(gè)方法,并且將對(duì)于方法的調(diào)用代碼編譯成一個(gè)緊湊的指針+偏移的調(diào)用的硬編碼。這種查找表的最大特點(diǎn)就是高效率,基于這種查找表進(jìn)行方法調(diào)用僅僅需要多做一次數(shù)組內(nèi)的隨機(jī)訪(fǎng)問(wèn)操作。在所有我們所能想到的“增加一個(gè)間接層”的方案中,這種方案在效率上是最高的。但是使用這種方案有一個(gè)限定,就是要求所有同族多態(tài)對(duì)象具有完全一樣的查找表。也就是說(shuō),你必須確保所有實(shí)現(xiàn)了某個(gè)接口的對(duì)象的虛方法查找表的第k 項(xiàng)都具有相同的語(yǔ)義。假設(shè)一個(gè)基類(lèi)有100個(gè)可供改寫(xiě)的虛方法,那么它的虛方法查找表共有100項(xiàng)(實(shí)際上就是100個(gè)指向方法入口地址的指針)。而其所有派生類(lèi)對(duì)象都必須有結(jié)構(gòu)上完全相同的、長(zhǎng)度至少為100項(xiàng)的虛方法查找表?,F(xiàn)在假設(shè)我們開(kāi)發(fā)的一個(gè)派生類(lèi)中只改寫(xiě)了基類(lèi)的5個(gè)方法,那么這個(gè)派生類(lèi)對(duì)象所共享的虛方法表仍然長(zhǎng)達(dá)100項(xiàng),只不過(guò)其中95項(xiàng)與其基類(lèi)對(duì)象虛方法查找表中相應(yīng)的項(xiàng)一模一樣,只有5項(xiàng)具有實(shí)際意義——正是這5項(xiàng)的存在才使派生類(lèi)的存在有了意義。

在這種情況下,該方法表的實(shí)際有效利用率只有可憐的5%??偟膩?lái)說(shuō),這一方案執(zhí)行效率最優(yōu),但是并不適用于所有的場(chǎng)合。

當(dāng)然,看上去上述兩種虛方法調(diào)用實(shí)現(xiàn)技術(shù)效果完全一樣,一切都被掩蓋在編譯器之下,與一般開(kāi)發(fā)者毫無(wú)關(guān)系。但是,事實(shí)真的如此嗎?我們?cè)谙旅鏁?huì)看到,C++ 的這種查找表結(jié)構(gòu)構(gòu)成了C++應(yīng)用開(kāi)發(fā)中最險(xiǎn)惡的技術(shù)陷阱之一。

兩種不同的多態(tài)性應(yīng)用場(chǎng)景

學(xué)習(xí)過(guò)數(shù)值分析的讀者應(yīng)該熟知,在矩陣運(yùn)算的電算求解領(lǐng)域,低階稠密矩陣的求解與高階稀疏矩陣的求解是性質(zhì)完全不同的兩個(gè)問(wèn)題,其存儲(chǔ)方案和求解算法截然不同。非常有趣的是,在多態(tài)性的實(shí)際應(yīng)用中,也有著與矩陣問(wèn)題類(lèi)似的兩種性質(zhì)上截然不同的場(chǎng)景。

第一種場(chǎng)景中,我們所構(gòu)造的對(duì)象比較簡(jiǎn)單,同一族系中兄弟類(lèi)總數(shù)不多,而彼此之間的差異較大,因此對(duì)象中的虛方法數(shù)量少,而改寫(xiě)率高。我們通常在教科書(shū)上所接觸的面向?qū)ο罄?,以及在一般?yīng)用領(lǐng)域中接觸的對(duì)象都屬此類(lèi)。

例如一個(gè)Modem類(lèi),即使其具有較多的特性,虛方法總數(shù)也很難超過(guò)20個(gè),而不同的Modem類(lèi)實(shí)現(xiàn),可能會(huì)改寫(xiě)其中大部分甚至全部虛方法。另一個(gè)例子是COM接口。由于COM組件思想基于接口,而一個(gè)粒度良好的接口必然是“瘦小精干”的。比如IMalloc接口只有6個(gè)方法(不包括從IUnknown繼承來(lái)的3 個(gè)方法),IPersistFile共5個(gè)方法,通常用戶(hù)自己寫(xiě)的COM接口中的方法數(shù)量也不超過(guò)20。而在實(shí)現(xiàn)COM接口是,幾乎總是需要改寫(xiě)全部方法。這與低階稠密矩陣非常相似,因此值得用最簡(jiǎn)單直接的查找表結(jié)構(gòu)來(lái)實(shí)現(xiàn)——速度快,而且簡(jiǎn)單直接。由于虛方法改寫(xiě)率高,查找表中的有效利用率較高。這種場(chǎng)景是C++多態(tài)性實(shí)現(xiàn)技術(shù)大大的用武之地,可以說(shuō)C++特色的虛方法調(diào)用機(jī)制就是用來(lái)應(yīng)對(duì)這種應(yīng)用的。

而第二種應(yīng)用場(chǎng)景截然不同,在這種場(chǎng)景中,對(duì)象比較復(fù)雜,特性稠密,行為變化多端,同一族系中兄弟對(duì)象數(shù)量龐大,而彼此之間大同小異。此種對(duì)象中的虛方法數(shù)量多,而改寫(xiě)率低。GUI系統(tǒng)和視頻游戲是這種應(yīng)用場(chǎng)景的典型代表。由于我們整天與Windows 系統(tǒng)打交道,所以用Windows GUI系統(tǒng)來(lái)說(shuō)明這種場(chǎng)景是最合適不過(guò)的了。我們知道,在Windows圖形界面上的幾乎所有實(shí)體從概念上講都是Window對(duì)象,因此構(gòu)成了一個(gè)對(duì)象族系。這個(gè)族系有三個(gè)突出的特點(diǎn)。一是行為多,特征多變(或者說(shuō)虛方法數(shù)量多)。Microsoft Windows系統(tǒng)直接定義了數(shù)百個(gè)窗口消息,并允許用戶(hù)使用WM_USER+n和WM_APP+n的方式定義新的消息,用面向?qū)ο蟮脑?huà)來(lái)說(shuō),就相當(dāng)于給Windows系統(tǒng)中的所有Window對(duì)象定義了數(shù)百個(gè)可供改寫(xiě)的虛方法,并且還允許用戶(hù)自由擴(kuò)展新的虛方法。

第二個(gè)特點(diǎn)是改寫(xiě)率低,同族對(duì)象之間大同小異。通常我們對(duì)于絕大多數(shù)的窗口消息都是用DefWindowProc來(lái)統(tǒng)一處理,或者用SendMessage函數(shù)將消息轉(zhuǎn)發(fā)(委托)給系統(tǒng)提供的標(biāo)準(zhǔn)窗口對(duì)象處理,這也就是相當(dāng)于把這些消息交給基類(lèi)窗口對(duì)象來(lái)處理,而只攔截(改寫(xiě))其中幾個(gè)至幾十個(gè)消息(方法)。相對(duì)于窗口對(duì)象族龐大的虛方法數(shù)量來(lái)說(shuō),改寫(xiě)率通常不超過(guò)20%。第三個(gè)特點(diǎn)是同族兄弟類(lèi)數(shù)量龐大。從標(biāo)準(zhǔn)窗口到異型窗口,從對(duì)話(huà)框到按鈕,從工具條到文本框,所有的一切都是Window,甚至于兩個(gè)按鈕看上去完全一樣,僅僅是caption不同,按下時(shí)執(zhí)行的操作不同,就需要用不同的類(lèi)來(lái)構(gòu)造。因此在一個(gè)普通規(guī)模的應(yīng)用程序GUI界面系統(tǒng)中,構(gòu)造上百個(gè)大同小異的窗口類(lèi)是并不奇怪的。任何一個(gè)對(duì)Win32 API有一定理解的開(kāi)發(fā)者,對(duì)此都不難體會(huì)。

從第1節(jié)對(duì)于C++虛方法調(diào)用機(jī)制的介紹可以很容易地知道,C++那種基于絕對(duì)位置的、不帶任何自描述信息的查找表結(jié)構(gòu),并不適用于上述的第二種場(chǎng)景。如果強(qiáng)行使用C++原生的對(duì)象模型來(lái)實(shí)現(xiàn)類(lèi)似Windows的GUI系統(tǒng),那么結(jié)果是這樣的:基類(lèi)(不妨設(shè)為KWindow類(lèi))要定義1000個(gè)虛方法(其中應(yīng)該留出多少位置供用戶(hù)擴(kuò)展之需呢?),從而擁有一個(gè)長(zhǎng)達(dá)1000的查找表,而所有的直接和間接派生類(lèi)對(duì)象,為了保持與KWindow 在方法查找表結(jié)構(gòu)上的兼容,都要至少包容一個(gè)長(zhǎng)達(dá)1000的查找表。

我們舉一個(gè)極端的例子來(lái)欣賞一下這種解決方案的荒謬性,假設(shè)有一個(gè)類(lèi)KPushButton從KWindow中派生,并通過(guò)改寫(xiě)20個(gè)虛方法實(shí)現(xiàn)了一個(gè)標(biāo)準(zhǔn)的按鈕控件,那么它的虛方法查找表中有多少項(xiàng)?對(duì)不起,不是20 項(xiàng),而是至少1000項(xiàng)(如果它沒(méi)有加入新的方法的話(huà)),其中絕大多數(shù)僅僅是KWindow虛方法表的原封不動(dòng)的克隆,只有20項(xiàng)屬于它自己,只有這20項(xiàng)真正有意義,方法表中980項(xiàng)被浪費(fèi)掉了。它們唯一的意義在于占據(jù)一些位置,使得“指針加偏移”的計(jì)算能夠繼續(xù)準(zhǔn)確地尋址。你以為事情已經(jīng)很糟糕了?不,事實(shí)上還可以更糟糕!

假設(shè)你需要一個(gè)標(biāo)準(zhǔn)按鈕,它的外觀(guān)、顏色、文字和其他行為都與KPushButton完全一樣,僅僅是相應(yīng)CLICK事件的操作不同,你需要怎么辦?顯然是從KPushButton中派生自己的KMyPush-ButtonOK類(lèi),然后改寫(xiě)其中的1 個(gè)方法(可能是叫做OnClick的)。那么在這個(gè)新的類(lèi)中,虛方法表是多長(zhǎng)呢?是1項(xiàng)嗎?不是。是20項(xiàng)嗎?也不是。實(shí)際上,是1000項(xiàng)!其中只有1項(xiàng)(OnClick)體現(xiàn)了它存在的意義,其他999項(xiàng)(在32位機(jī)器上占據(jù)3996個(gè)字節(jié))幾乎完全被浪費(fèi)掉了!一個(gè)中等規(guī)模的應(yīng)用程序中安排幾十個(gè)界面,數(shù)百個(gè)自定制控件,則僅在虛方法表上浪費(fèi)的存儲(chǔ)空間即達(dá)到數(shù)百KB甚至1MB以上。也許這個(gè)數(shù)字在今天用GB 大筐裝主存的時(shí)代實(shí)在是小兒科,但是其背后所體現(xiàn)的思路之丑陋卻是任何一個(gè)有點(diǎn)良心的開(kāi)發(fā)者(尤其是C++開(kāi)發(fā)者)所不能容忍的。

也正是因?yàn)檫@個(gè)原因,從OWL 到VCL,.. 從MFC到Qt,以至于近幾年出現(xiàn)的GUI和游戲開(kāi)發(fā)框架,所有涉及大量事件行為的C++ GUI Framework沒(méi)有一家使用標(biāo)準(zhǔn)的C++多態(tài)技術(shù)來(lái)構(gòu)造窗口類(lèi)層次,而是各自為戰(zhàn),發(fā)明出五花八門(mén)的技術(shù)來(lái)繞過(guò)這個(gè)暗礁。其中比較經(jīng)典的解決方案有三,分別以VCL 的動(dòng)態(tài)方法、MFC的全局事件查找表和Qt 的Signal/Slot為代表。而其背后的思想是一致的,用Grady Booch的一句話(huà)來(lái)總結(jié),就是:“當(dāng)你發(fā)現(xiàn)系統(tǒng)中需要大量相似的小型類(lèi)的時(shí)候,應(yīng)當(dāng)用大量相似的小型對(duì)象解決之。”2 也就是說(shuō),將一些本來(lái)會(huì)導(dǎo)致需要派生新類(lèi)來(lái)解決的問(wèn)題,用實(shí)例化新的對(duì)象來(lái)解決。這種思路幾乎必然導(dǎo)致類(lèi)似C#中delegate那樣的機(jī)制成為必需品??上У氖牵瑯?biāo)準(zhǔn)C++ 不支持delegate。雖然C++社群里有很多人做了各種努力,應(yīng)用了諸如template、functor等高級(jí)技巧,但是在效果上距離真正的delegate還有差距。因此,為了保持解決方案的簡(jiǎn)單,Borland C++Builder擴(kuò)展了__closure關(guān)鍵字,MFC發(fā)明出一大堆怪模怪樣的宏,Qt搞了一個(gè)moc前處理器,八仙過(guò)海,各顯神通。

讓我們小結(jié)一下,面向?qū)ο蠖鄳B(tài)性有兩種不同的應(yīng)用場(chǎng)景,而C++的標(biāo)準(zhǔn)多態(tài)技術(shù)只適合其中一種,對(duì)于另一種并不適合,必須以其他機(jī)制實(shí)現(xiàn)。

解決思路和建議

或許有讀者讀到這里,會(huì)對(duì)C++產(chǎn)生很大的懷疑。需要說(shuō)明的是,C++選擇的多態(tài)性實(shí)現(xiàn)技術(shù)是完全符合C++哲學(xué)的。而且,C++允許你以各種可能的辦法來(lái)解決這個(gè)問(wèn)題。時(shí)至今日,依靠各種成熟的GUI框架,大多數(shù)情況下我們可以自動(dòng)繞過(guò)暗礁。

問(wèn)題的嚴(yán)重性在于,由于C++教育上的問(wèn)題,很多開(kāi)發(fā)者對(duì)于C++原生多態(tài)技術(shù)在上述第二種應(yīng)用場(chǎng)合中的局限性認(rèn)識(shí)不足,因此當(dāng)他們面臨類(lèi)似的問(wèn)題時(shí),會(huì)不自覺(jué)地踏入陷阱中。在此我愿提醒C++開(kāi)發(fā)者,當(dāng)你面對(duì)的系統(tǒng)中含有標(biāo)準(zhǔn)的事件處理特征,而且事件數(shù)量較大時(shí),請(qǐng)慎重考慮你的類(lèi)層次結(jié)構(gòu)設(shè)計(jì)??梢钥紤]模仿MFC或者Qt的解決方法,但在我看來(lái),一個(gè)更加直接而且簡(jiǎn)單的方法是,模擬本文第1節(jié)中描述的、基于字符串比較的方法查找表,用一個(gè)單一的消息分發(fā)對(duì)象來(lái)向各個(gè)對(duì)象分發(fā)消息。由于這個(gè)消息分發(fā)對(duì)象會(huì)經(jīng)常需要調(diào)整變化,將它單獨(dú)放在一個(gè)DLL 甚至COM組件中,在運(yùn)行時(shí)加載到進(jìn)程內(nèi)。這種方案不是最精巧的,但是在大多數(shù)情況下有效,并且實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單。限于篇幅,這里不詳細(xì)描述。

事實(shí)上,我本人認(rèn)為,C++語(yǔ)言應(yīng)當(dāng)從編譯器上解決這個(gè)問(wèn)題?;舅悸窞?,當(dāng)基類(lèi)虛方法數(shù)量大而派生類(lèi)改寫(xiě)的方法數(shù)量小的時(shí)候(這個(gè)信息可以從編譯過(guò)程中得到),改變派生類(lèi)對(duì)象的虛方法查找機(jī)制,改按位置查找為按被調(diào)用函數(shù)實(shí)際信息查找。這樣一來(lái),派生類(lèi)中的虛方法表可不必與基類(lèi)保持結(jié)構(gòu)上的一致,從而避免了空間上的浪費(fèi)。這種思路跟Delphi/Object Pascal語(yǔ)言中dynamic關(guān)鍵字有相似之處。本文不再贅述。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • C++
    C++
    +關(guān)注

    關(guān)注

    22

    文章

    2108

    瀏覽量

    73657

原文標(biāo)題:C++多態(tài)技術(shù)的實(shí)現(xiàn)和反思

文章出處:【微信號(hào):C_Expert,微信公眾號(hào):C語(yǔ)言專(zhuān)家集中營(yíng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    34063的局限性

    由34063構(gòu)成的開(kāi)關(guān)電源雖然價(jià)格便宜、應(yīng)用廣泛,但它的局限性也是顯而易見(jiàn)的。主要有以下幾點(diǎn):(1)效率偏低。對(duì)于降壓應(yīng)用,效率一般只有70%左右,輸出電壓低時(shí)效率更低。這就使它不能用在某些對(duì)功耗
    發(fā)表于 06-12 10:41

    無(wú)線(xiàn)網(wǎng)絡(luò)有什么局限性

    以無(wú)線(xiàn)方式發(fā)送數(shù)據(jù)的方法有很多。從遙控?zé)o鑰匙進(jìn)入(RKE)和車(chē)庫(kù)開(kāi)門(mén)裝置(GDO)等簡(jiǎn)單命令和控制方案到WLAN,您有很多種選擇。本文主要探討各種可用的無(wú)線(xiàn)網(wǎng)絡(luò)選項(xiàng)和必須在應(yīng)用過(guò)程中解決的局限性,旨在為設(shè)計(jì)師提供一些選擇工業(yè)應(yīng)用的無(wú)線(xiàn)網(wǎng)絡(luò)時(shí)所需的實(shí)用信息。
    發(fā)表于 08-23 06:13

    運(yùn)算放大器的精度局限性是什么

    日益普遍。本文將介紹運(yùn)算放大器的精度局限性,以及如何選擇為數(shù)不多的有可能達(dá)到 1 ppm 精度的運(yùn)算放大器。另外,我們還將介紹一些針對(duì)現(xiàn)有運(yùn)算放大器局限性的應(yīng)用改善。
    發(fā)表于 03-11 06:10

    如何完備地實(shí)現(xiàn)C++多態(tài)性?

    如何完備地實(shí)現(xiàn)C++多態(tài)性?虛函數(shù)怎么使用?
    發(fā)表于 04-28 06:44

    基于Java多態(tài)性的應(yīng)用程序設(shè)計(jì)

    Java 中的多態(tài)體現(xiàn)在類(lèi)的繼承和實(shí)現(xiàn)接口等方面。通過(guò)對(duì)與多態(tài)有關(guān)的概念進(jìn)行歸納比較,從繼承和接口兩方面對(duì)多態(tài)的正確實(shí)現(xiàn)進(jìn)行分析,結(jié)合實(shí)例說(shuō)明多態(tài)性在程序設(shè)計(jì)中的
    發(fā)表于 09-09 08:51 ?24次下載

    什么是方法的重載(多態(tài)性)?

    什么是方法的重載(多態(tài)性)? 在同一個(gè)類(lèi)中至少有兩個(gè)方法用同一個(gè)名字,但有不同的參數(shù)。
    發(fā)表于 04-28 14:28 ?1274次閱讀
    什么是方法的重載(<b class='flag-5'>多態(tài)性</b>)?

    C++的動(dòng)態(tài)多態(tài)和靜態(tài)多態(tài)

    多態(tài)C++ 中面向?qū)ο?b class='flag-5'>技術(shù)的核心機(jī)制之一包含靜態(tài)多態(tài)和動(dòng)態(tài)多態(tài)它們之間有一定的相似但是應(yīng)用
    發(fā)表于 06-29 15:41 ?41次下載
    <b class='flag-5'>C++</b>的動(dòng)態(tài)<b class='flag-5'>多態(tài)</b>和靜態(tài)<b class='flag-5'>多態(tài)</b>

    數(shù)據(jù)的共享和保護(hù)以及多態(tài)性_實(shí)驗(yàn)4

    c++面向?qū)ο笳n程實(shí)驗(yàn)指導(dǎo)書(shū)題目_數(shù)據(jù)的共享和保護(hù)以及多態(tài)性。
    發(fā)表于 01-14 16:25 ?0次下載

    java多態(tài)性的實(shí)現(xiàn)

    Java中多態(tài)性的實(shí)現(xiàn) 什么是多態(tài) 面向?qū)ο蟮娜筇匦裕悍庋b、繼承、多態(tài)。從一定角度來(lái)看,封裝和繼承幾乎都是為多態(tài)而準(zhǔn)備的。這是我們最后一個(gè)概念,也是最重要的知識(shí)點(diǎn)。
    發(fā)表于 09-27 10:36 ?9次下載

    C++程序設(shè)計(jì)教程之多態(tài)性與虛函數(shù)的詳細(xì)資料說(shuō)明

    本文檔詳細(xì)介紹的是C++程序設(shè)計(jì)教程之多態(tài)性與虛函數(shù)的詳細(xì)資料說(shuō)明主要資料包括了:1 多態(tài)性的概念,2 一個(gè)典型的例子,3 虛函數(shù),4 純虛函數(shù)與抽象類(lèi)
    發(fā)表于 03-14 16:39 ?5次下載
    <b class='flag-5'>C++</b>程序設(shè)計(jì)教程之<b class='flag-5'>多態(tài)性</b>與虛函數(shù)的詳細(xì)資料說(shuō)明

    MISRA C++針對(duì)使用多態(tài)性的規(guī)避方法與建議

    本文主要介紹兩類(lèi)在實(shí)現(xiàn)形式的多態(tài)性中需要注意的一些問(wèn)題:一是運(yùn)算符的重載,這是編譯時(shí)的多態(tài)性,即程序在編譯時(shí)就能根據(jù)重載的情況確定需要調(diào)用的函數(shù);二是虛函數(shù)的使用,這是運(yùn)行時(shí)的多態(tài)性,即在程序執(zhí)行前,無(wú)法根據(jù)函數(shù)名和參數(shù)來(lái)確定調(diào)
    的頭像 發(fā)表于 09-07 18:41 ?3556次閱讀
    MISRA <b class='flag-5'>C++</b>針對(duì)使用<b class='flag-5'>多態(tài)性</b>的規(guī)避方法與建議

    WSN中LEACH協(xié)議局限性的分析與改進(jìn)

    WSN中LEACH協(xié)議局限性的分析與改進(jìn)(電源技術(shù)答案)-WSN中LEACH協(xié)議局限性的分析與改進(jìn)? ? ? ? ? ? ? ?
    發(fā)表于 09-15 11:12 ?3次下載
    WSN中LEACH協(xié)議<b class='flag-5'>局限性</b>的分析與改進(jìn)

    多態(tài)性實(shí)現(xiàn)原理及其在面向?qū)ο缶幊讨械膽?yīng)用

    在面向?qū)ο蟮木幊讨校?b class='flag-5'>多態(tài)性是一個(gè)非常重要的概念。
    的頭像 發(fā)表于 06-08 14:19 ?630次閱讀

    千兆光模塊存在哪些局限性?

    千兆光模塊,作為網(wǎng)絡(luò)設(shè)備中常用的一個(gè)配件,在實(shí)際應(yīng)用中,由于其存在一定的局限性,可能會(huì)對(duì)網(wǎng)絡(luò)傳輸速度、信號(hào)接收等方面產(chǎn)生影響。本文將就千兆光模塊的局限性進(jìn)行探討,并提供一些可能的解決方案。
    的頭像 發(fā)表于 10-16 12:10 ?581次閱讀

    WDM技術(shù)的缺點(diǎn)和局限性

    和效率。然而,盡管WDM技術(shù)具有諸多優(yōu)勢(shì),但它也存在一些缺點(diǎn)和局限性。以下是對(duì)WDM技術(shù)缺點(diǎn)和局限性的詳細(xì)分析:
    的頭像 發(fā)表于 08-09 11:42 ?808次閱讀