生活随笔
收集整理的這篇文章主要介紹了
C++静态多态(模版模拟多态)的讨论
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
說到面向?qū)ο筇匦灾弧岸鄳B(tài)”,以我的水平已經(jīng)說不出太多新意了。相信很多程序員代碼K多了,做夢都在“多態(tài)中”運行著。常規(guī)的多態(tài)是C++語義內(nèi)置支持的一種特性,通過虛函數(shù)可以實現(xiàn)這個特性,為了后面以示區(qū)別,我們姑且把這種多態(tài)稱為“動態(tài)多態(tài)”或”運行期多態(tài)“,而本文總主要想討論下“靜態(tài)多態(tài)”,也可以叫“編譯期多態(tài)”,同時一起來看下,靜態(tài)多態(tài)會給我們帶來哪些驚喜之處,拭目以待吧。?
首先看個正常通過虛函數(shù)實現(xiàn)多態(tài)的常規(guī)例子,如下所示,很簡單明了無需多言。
[cpp]?view plaincopy
#include?<iostream>?? #include?<string>?? ?? class?BasicClassic?? {?? public:?? ???????virtual?void?Print()?=?0;?? };?? ?? class?DerivedClassic1?:?public?BasicClassic?? {?? public:?? ??????DerivedClassic1()?{}?? ?? ???????virtual?void?Print()?{?? ????????????std::cout?<<?"DerivedClassic1?Print"?<<?std::endl;?? ??????}?? };?? ?? class?DerivedClassic2?:?public?BasicClassic?? {?? public:?? ??????DerivedClassic2()?{}?? ?? ???????virtual?void?Print()?{?? ????????????std::cout?<<?"DerivedClassic2?Print"?<<?std::endl;?? ??????}?? };??
通過虛函數(shù),在運行時通過虛函數(shù)表指針,通過索引找到對應(yīng)函數(shù),然后進行調(diào)用,所以前面我們稱之為動態(tài)多態(tài)或運行時多態(tài)。那靜態(tài)多態(tài)又是怎么回事,如何實現(xiàn)呢?答案是模版。如果熟悉COM的同學應(yīng)該見過框架中很多通過模版來實現(xiàn)多態(tài)的實現(xiàn),看下如下的實現(xiàn):
[cpp]?view plaincopy
template<typename?Derived>?? class?Basic?? {?? public:?? ???????inline?void?Print()?{?? ????????????SelfCast()->Print();?? ??????}?? ?? protected:?? ???????inline?Derived*?SelfCast()?{?? ?????????????return?static_cast?<Derived*>(this);?? ??????}?? };?? class?Derived1?:?public?Basic<Derived1>?? {?? public:?? ??????Derived1()?{}?? ?? ??????inline?void?Print()?{?? ????????????std::cout?<<?"Derived1?Print"?<<?std::endl;?? ??????}?? };?? class?Derived2?:?public?Basic<Derived2>?? {?? public?:?? ??????Derived2()?{}?? ?? ???????inline?void?Print()?{?? ????????????std::cout?<<?"Derived2?Print"?<<?std::endl;?? ??????}?? ?? ???????static?std::string?Name()?{?? ?????????????return?"Derived2?Class"?;?? ??????}?? };?? 具體使用的代碼: [cpp]?view plaincopy
Basic<Derived1>*?der1?=?new?Derived1();?? der1->Print();?? Basic<Derived2>*?der2?=?new?Derived2();?? der2->Print();?? 輸出結(jié)果: Derived1 Print Derived2 Print
這里實現(xiàn)的關(guān)鍵是SelfCast函數(shù),通過static_cast把當前對象強制轉(zhuǎn)換為具體指定的子類對象,這里是Derived1。其實實現(xiàn)的原理很簡單,不難理解,我們需要重點討論的是,這么樣實現(xiàn)的多態(tài)跟常規(guī)虛函數(shù)的做法到底有什么不同,有什么優(yōu)勢?
大家應(yīng)該都知道,虛函數(shù)的使用會帶來額外的開銷,具有虛函數(shù)的class類型都需要一張?zhí)摵瘮?shù)表,而每多一個虛函數(shù),對應(yīng)類型的對象的大小就會增加4bytes(32位機器下),夸張的試想一下如果有10個父類,每個父類都有100個虛函數(shù)的情況下,每個對象會增加多少? 4x10x100=4000bytes! 除了空間上的開銷,每個虛函數(shù)的調(diào)用在時間上都會比普通函數(shù)多一次整形加法和一次指針間接引用,也就是時間上的開銷。 這種開銷雖然在絕大多數(shù)的應(yīng)用中都是可以忽略不計的,但是總會存在一些對性能與開銷無比在意的關(guān)鍵代碼。根據(jù)28法則,應(yīng)用中80%的時間都是在運行其中20%的代碼,那么有時候?qū)@20%代碼的優(yōu)化也許會帶來顯著的改善。 回到正題,我們把傳統(tǒng)的實現(xiàn)方式稱為動態(tài)多態(tài),而模板方式的實現(xiàn)則是靜態(tài)多態(tài),歸納下他們的區(qū)別: 動態(tài)多態(tài)的多態(tài)性是在運行期決定的,而靜態(tài)多態(tài)是在編譯期就決定的動態(tài)多態(tài)的實現(xiàn)需要更多空間上的開銷,每個對象會因為一個虛函數(shù)而增加4bytes,靜態(tài)多態(tài)則沒有這個問題動態(tài)多態(tài)的實現(xiàn)需要更多的時間開銷,虛函數(shù)的調(diào)用在時間上都會比普通函數(shù)多一次整形加法和一次指針間接引用,靜態(tài)多態(tài)中的調(diào)用則跟普通函數(shù)的調(diào)用開銷相同動態(tài)多態(tài)(虛函數(shù))是C++編譯器內(nèi)置支持的一種實現(xiàn)方式,而靜態(tài)多態(tài)則會額外帶來一些使用的復(fù)雜性動態(tài)多態(tài)中虛函數(shù)不能通過內(nèi)聯(lián)來優(yōu)化執(zhí)行效率,而靜態(tài)多態(tài)中則可以通過內(nèi)聯(lián)來進一步優(yōu)化函數(shù)執(zhí)行效率
綜上所述,在實際使用中,到底選擇哪種實現(xiàn)方式,要因需而異,如果沒有特別的性能需求時,完全沒有必要為了寫的更酷而去使用模版的方式來實現(xiàn),反而得不償失,但如果針對特別需求或關(guān)鍵性能的代碼,則可以考慮這種優(yōu)化。
另外再看一種使用方式,模版還可以實現(xiàn)static函數(shù)的類似多態(tài)特性,如下所示: [cpp]?view plaincopy
template?<typename?Derived>?? class?Basic?? {?? public?:?? ??????Basic()?{??}?? ?? ???????inline?void?Print()?{?? ????????????std::cout?<<?Basic<Derived>::Name()?<<?std::endl;?? ????????????SelfCast()->Print();?? ??????}?? ?? ???????static?std::string?Name()?{?? ?????????????return?Derived::Name();?? ??????}?? ?? protected?:?? ???????inline?Derived*?SelfCast()?{?? ?????????????return?static_cast?<Derived*>(?this);?? ??????}?? };?? ?? class?Derived1?:?public?Basic<Derived1>?? {?? public?:?? ??????Derived1()?{}?? ?? ???????inline?void?Print()?{?? ????????????std::cout?<<?"Derived1?Print"?<<?std::endl;?? ??????}?? ?? ???????static?std::string?Name()?{?? ?????????????return?"Derived1?Class"?;?? ??????}?? };?? 也就是說針對某些希望定義為static的函數(shù),當你希望能在基類抽象方法中根據(jù)當前對象具體類型來使用子類相應(yīng)static函數(shù)時,如上方法可以達成你的目的,這未嘗不是一種不錯的實現(xiàn)方式。 ok,靜態(tài)多態(tài)就說到這,延伸還有哪些特定的應(yīng)用,歡迎大家一起討論。 ========================================================================= c++的模板是個很強很暴力的東西,可以輕松地模擬多態(tài)。下面舉個例子:
====================================================================
#include <iostream>
#include <string>
using namespace std;
class StarDecorator//注意:與多態(tài)不同,不需要有類階層(簡單說不需要繼承啥接口)
{
public:
? ?void printHead()
? ?{
? ? ? ?cout << "**********" << endl;
? ?}
? ?void printTail()
? ?{
? ? ? ?cout << "**********" << endl;
? ?}
};
class AddDecorator
{
public:
? ?void printHead()
? ?{
? ? ? ?cout << "++++++++++" << endl;
? ?}
? ?void printTail()
? ?{
? ? ? ?cout << "++++++++++" << endl;
? ?}
};
template<class Decorator>
class Printer
{
public:
? ?void print(const string& str)
? ?{
? ? ? ?decorator.printHead();
? ? ? ?cout << str << endl;
? ? ? ?decorator.printTail();
? ?}
private:
? ?Decorator decorator;
};
int main(int argc, char* argv[])
{
? ?Printer<StarDecorator> p1;
? ?p1.print("Hello,World!");
??
? ?Printer<AddDecorator> p2;
? ?p2.print("Hello,World!");
? ?return 0;
}
========================================
? ?是不是很像多態(tài)?更具體地說是設(shè)計模式中的Strategy模式。
? ?這么做的好處:
? ?1)比用多態(tài)時簡單,不需要先構(gòu)建Strategy對象再傳入構(gòu)造函數(shù),故構(gòu)造對象的代碼簡潔。
? ?2)靈活機動,不需要類階層,只要實現(xiàn)相關(guān)接口就可以召之即來。如果沒有實現(xiàn)相關(guān)接口會有明顯的編譯錯誤提示。
? ?這么做的缺點——和c++模板的缺點是一樣的:
? ?1)易讀性比較不好,調(diào)試比較困難
? ?2)模板只能定義在.h文件中,當工程大了之后,編譯時間十分的變態(tài)。
??
? ?結(jié)論:有些場合可以讓代碼較簡潔,但應(yīng)避免在比較底層的地方使用。
?
評論:
? ? 這是一個比較普遍的例子,實現(xiàn)通過傳遞不同的模板類型參數(shù),實現(xiàn)對不同類的功能的調(diào)用,
這就需要一個調(diào)用公共接口。這個接口 可以用函數(shù)模板來充當,也可以用類模板來充當。
? ? 如果用類模板來充當,這個類模板可以是一個任意的類模板,也可以將類繼承派生機制用起來,使用具體類的基類作為公共接口。
? WTL中就是這么干的。比如窗口類的派生類,在向其基類模板中傳遞參數(shù)時,將自身類名傳遞給基類的模板參數(shù),這樣,就實現(xiàn)在基類這個公共調(diào)用接口中 實現(xiàn)對派生類的調(diào)用!!!
這種方式優(yōu)雅地將 繼承、派生機制 和模板機制有機結(jié)合起來。
總結(jié)
以上是生活随笔為你收集整理的C++静态多态(模版模拟多态)的讨论的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。