C++ 宏、范型和RTTI 浅析
? ? ? ?RTTI(Run-Time?Type?Identification)是面向對象程序設計中一種重要的技術。
現(xiàn)行的C++標準對RTTI已經(jīng)有了明白的支持。
只是在某些情況下出于特殊的開發(fā)須要,我們須要自己編碼來實現(xiàn)。本文介紹了一些關于RTTI的基礎知識及其原理和實現(xiàn),并分析比較三者是線上的差異與聯(lián)系。
【正文】
RTTI 的需求
? ? ? ?和非常多其它語言一樣,C++是一種靜態(tài)類型語言。其數(shù)據(jù)類型是在編譯期就確定的,不能在執(zhí)行時更改。然而因為面向對象程序設計中多態(tài)性的要求,C++中的指針或引用(Reference)本身的類型,可能與它實際代表(指向或引用)的類型并不一致。有時我們須要將一個多態(tài)指針轉換為事實上際指向對象的類型。就須要知道執(zhí)行時的類型信息。這就產(chǎn)生了執(zhí)行時類型識別的要求。
C++對RTTI的支持
? ? ?C++提供了兩個keywordtypeid和dynamic_cast,一個類type_info來支持RTTI。
? ?? dynamic_cast操作符:它同意在執(zhí)行時刻進行類型轉換,從而使程序可以在一個類層次結構安全地轉換類型。dynamic_cast提供了兩種轉換方式。把基類指針轉換成派生類指針,或者把指向基類的左值轉換成派生類的引用。
見下例講述:
void company::payroll(employee *pe) { //對指針轉換失敗,dynamic_cast返回NULL if(programmer *pm=dynamic_cast(pe)){ pm->bonus(); } }void company::payroll(employee &re) { try{ //對引用轉換失敗的話,則會以拋出異常來報告錯誤 programmer &rm=dynamic_cast(re); pm->bonus(); } catch(std::bad_cast){ } }? ? ? ? ?這里bonus是programmer的成員函數(shù),基類employee不具備這個特性。所以我們必須使用安全的由基類到派生類類型轉換,識別出programmer指針。
? ? ??typeid操作符:它指出指針或引用指向的對象的實際派生類型。
? ? ? ?比如:
employee* pe=new manager; typeid(*pe)==typeid(manager) //true ? ? ? ?typeid能夠用于作用于各種類型名,對象和內置基本數(shù)據(jù)類型的實例、指針或者引用,當作用于指針和引用將返回它實際指向對象的類型信息。typeid的返回是type_info類型。
? ? ? ?type_info類:這個類的確切定義是與編譯器實現(xiàn)相關的。以下是《C++?Primer》中給出的定義(參考資料[2]中談到編譯器必須提供的最小信息量):
class type_info { private: type_info(const type_info&); type_info& operator=( const type_info& ); public: virtual ~type_info(); int operator==( const type_info& ) const; int operator!=( const type_info& ) const; const char* name() const; };
詳見:http://bbs.csdn.net/topics/40414128
三者比較:
宏能夠在編譯前用字符替換的辦法展開,減輕程序猿反復編碼的工作量。
c++的范型(模版)也是在編譯時確定終于的程序樣式。他用的辦法是編譯時確定類型信息。
RTTI是執(zhí)行期類型信息,能夠在執(zhí)行時得到對象的類型信息。
我們考察一個程序,為了說明問題,我特意找了一個簡單的程序,這個程序比較a和b,假設a大于b就交換他們。可是。a、b的類型并不確定可能是字符串也可能是整數(shù)還可能是復數(shù)。為了簡潔和不至于造成過的混淆,我不使用操作符重載。假定不論什么操作都是基于對象方法的,為了完畢這個函數(shù)。a、b必須支持compare(比較)和swape(交換)方法。
我們不清楚a、b的類型,假設有3種類型我們就必須寫3個函數(shù)嗎?那太累人了。我們用宏來定義這個函數(shù)好了。
#define?exchange(a,b)?if(a.compare(b))a.swape(b);
這樣我們在使用的時候就能夠直接使用exchange宏來表達這個函數(shù),并且能夠適應各種類型,僅僅要他們都支持這兩個函數(shù)就能夠。
我們還能夠用范型來實現(xiàn)這個函數(shù)
template<typename?T>
void?exchange(T?&a,?T?&b)
{
??if(a.compare(b))a.swape(b)
}
我們相同達到了目的。
假設編譯器支持豐富的RTTI,我們還能夠用腳本語言的方式來實現(xiàn)他們。
exchange(a,?b)
{
??if(a.compare(b))a.swape(b);
}
上面三種方式區(qū)別在哪里呢?
第一種。使用字符替換的方式,在編譯前展開宏,使之成為程序中的一段代碼。
另外一種,在編譯時。確定調用函數(shù)的參數(shù)的類型,并自己主動生成一個這個類型的暫時函數(shù)。
第三種。在執(zhí)行時依據(jù)參數(shù)的類型確定是否可以執(zhí)行這段程序。
前2種都是在編譯時確認的。第三種是在執(zhí)行時確定的。
在程序設計中有著大量的反復代碼,我們須要一種方法來提高效率,可是為什么看著結構類似的程序須要反復代碼呢?最重要的原因是,傳統(tǒng)的程序中實體(函數(shù)、變量、屬性等等)在編譯時都須要內存中一塊確定的地址(或者相對基址的偏移)來指代。這時cpu處理方式的內在要求,而這個和程序設計時依照名字引用的思維習慣是不一致的。
我們能夠用宏和模版來取代手工對每一個類型的特化,可是在程序中仍然是使用地址來指代實體的。實際上每一個類型的特化程序依舊存在,僅僅是在程序設計外觀上不可見了。
第三種方式。使用RTTI。程序中的實體都不再是確定的地址來指代,而是通過字符串名稱(或者實體表)來指代,在執(zhí)行時依據(jù)名稱來特化。這樣的方法和前2個方法是本質的不同。
使用RTTI能夠在非常大程度上減輕宏和靜態(tài)模版帶來的副作用,使程序具有更加優(yōu)雅的外觀。
可是。C++的宏和靜態(tài)模版也不是一無是處。他用在對效率更加嚴格場合是很合適的。
轉載于:https://www.cnblogs.com/llguanli/p/8286541.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結
以上是生活随笔為你收集整理的C++ 宏、范型和RTTI 浅析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android抽奖动画,Android
- 下一篇: PostgreSQL extra_flo