摘要:
RTTI(Run-Time Type Identification)是面向?qū)ο蟪绦蛟O(shè)計(jì)中一種重要的技術(shù)。現(xiàn)行的C++標(biāo)準(zhǔn)對(duì)RTTI已經(jīng)有了明確的支持。不過(guò)在某些情況下出于特殊的開(kāi)發(fā)需要,我們需要自己編碼來(lái)實(shí)現(xiàn)。本文介紹了一些關(guān)于RTTI的基礎(chǔ)知識(shí)及其原理和實(shí)現(xiàn)。
RTTI需求:
和很多其他語(yǔ)言一樣,C++是一種靜態(tài)類型語(yǔ)言。其數(shù)據(jù)類型是在編譯期就確定的,不能在運(yùn)行時(shí)更改。然而由于面向?qū)ο蟪绦蛟O(shè)計(jì)中多態(tài)性的要求,C++中的指針或引用(Reference)本身的類型,可能與它實(shí)際代表(指向或引用)的類型并不一致。有時(shí)我們需要將一個(gè)多態(tài)指針轉(zhuǎn)換為其實(shí)際指向?qū)ο蟮念愋停托枰肋\(yùn)行時(shí)的類型信息,這就產(chǎn)生了運(yùn)行時(shí)類型識(shí)別的要求。
C++對(duì)RTTI的支持:
C++提供了兩個(gè)關(guān)鍵字typeid和dynamic_cast和一個(gè)type_info類來(lái)支持RTTI:
dynamic_cast操作符:它允許在運(yùn)行時(shí)刻進(jìn)行類型轉(zhuǎn)換,從而使程序能夠在一個(gè)類層次結(jié)構(gòu)安全地轉(zhuǎn)換類型。dynamic_cast提供了兩種轉(zhuǎn)換方式,把基類指針轉(zhuǎn)換成派生類指針,或者把指向基類的左值轉(zhuǎn)換成派生類的引用。見(jiàn)下例講述:
void company::payroll(employee *pe) {
//對(duì)指針轉(zhuǎn)換失敗,dynamic_cast返回NULL
if(programmer *pm=dynamic_cast(pe)){
pm->bonus();
}
}
void company::payroll(employee &re) {
try{
//對(duì)引用轉(zhuǎn)換失敗的話,則會(huì)以拋出異常來(lái)報(bào)告錯(cuò)誤
programmer &rm=dynamic_cast(re);
pm->bonus();
}
catch(std::bad_cast){
}
}
這里bonus是programmer的成員函數(shù),基類employee不具備這個(gè)特性。所以我們必須使用安全的由基類到派生類類型轉(zhuǎn)換,識(shí)別出programmer指針。
typeid操作符:它指出指針或引用指向的對(duì)象的實(shí)際派生類型。
例如:
employee* pe=new manager;
typeid(*pe)==typeid(manager) //true
typeid可以用于作用于各種類型名,對(duì)象和內(nèi)置基本數(shù)據(jù)類型的實(shí)例、指針或者引用,當(dāng)作用于指針和引用將返回它實(shí)際指向?qū)ο蟮念愋托畔ⅰypeid的返回是type_info類型。
type_info類:這個(gè)類的確切定義是與編譯器實(shí)現(xiàn)相關(guā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;
};
實(shí)現(xiàn)目標(biāo):
實(shí)現(xiàn)的方案
方案一:利用多態(tài)來(lái)取得指針或應(yīng)用的實(shí)際類型信息
這是一個(gè)最簡(jiǎn)單的方法,也是作者目前所采用的辦法。
實(shí)現(xiàn):
enum ClassType{
UObjectClass,
URectViewClass,
UDialogClass,
……
};
class UObject{
virtual char* GetClassName() const {
return "UObject";
};
virtual ClassType TypeOfClass(){
return UObjectClass;
};
};
class UDialog{
virtual char* GetClassName() const {
return "UDialog";
};
virtual ClassType TypeOfClass(){
return UDialogClass;
};
};
示例:
UObject po=new UObject;
UObject pr=new URectView;
UObject pd=new UDialog;
cout << "po is a " << po->GetClassName() << endl;
cout << "pr is a " << pr->GetClassName() << endl;
cout << "pd is a " << pd->GetClassName() << endl;
cout<TypeOfClass()==UObjectClass<