c++中的執行時型別檢查
簡介經常有人問到:「我怎樣才能在執行時確定或檢查c++中物件的型別呢?」,下面通過乙個簡單問題來作一演示。
以下程式會在第一次呼叫cfoo::animalsays 時顯示「bark!」,而第二次呼叫時顯示「miaou」。
class animal ;
class dog : public animal ;
class cat : public animal ;
class cfoo
};int main(int argc, char* argv)
也就是說,你需要用某種方法在執行時來確定函式 cfoo::animalsays接受的引數,到底是指向dog型別物件的指標,還是指向cat型別物件的指標。
第一次嘗試
我們的第乙個想法是新增乙個成員變數,其儲存了型別的相關資訊。
#include
class animal;};
class dog : public animal
const animaltype m_type;
};class cat : public animal
const animaltype m_type;
};class cfoo
;int main(int argc, char* argv)
void cfoo::animalsays(animal* panimal)
現在,回過頭看一下 cfoo::animalsays函式的實現部分,試想我們如果不只有兩種動物型別,而是50多種呢(也就是說,從animal的派生類)?這樣一來,不但**非常難看,還很難保證不出錯,也難於閱讀、修改、維護,這可不是乙個好的解決方案。
另乙個好點的方法
在靜態成員變數中儲存類名,通過虛函式來訪問。
#include
#include
class animal
;class dog : public animal
;class cat : public animal
;class cfoo
;int main(int argc, char* argv)
const string dog::m_class_name = "dog";
const string cat::m_class_name = "cat";
bool dog::isoftype(const std::string& class_name)
bool cat::isoftype(const std::string& class_name)
void cfoo::animalsays(animal* panimal)
cfoo::animalsays現在看上去乾淨多了,比前一種方法也易於閱讀,但還能新增兩個巨集來進一步簡化**:
#include
#include
#define declare_runtime_class /
private: static const std::string m_class_name; /
public: virtual bool isoftype(const std::string&);
#define implement_runtime_class(class_name) /
const std::string class_name##::m_class_name = #class_name; /
bool class_name##::isoftype(const std::string& name) /
// ...
這樣一來,以後就能新增更小的**塊了。
// ...
class animal
;class dog : public animal
;class cat : public animal
;class cfoo
;int main(int argc, char* argv)
implement_runtime_class(dog)
implement_runtime_class(cat)
void cfoo::animalsays(animal* panimal)
現在,已經非常接近mfc的解決方案了。
如果使用mfc,這種問題簡直是「小菜一碟」。大多數mfc類派生自cobject,而cobject連同一些新的mfc巨集都新增了對執行時型別資訊的支援,解決上述問題的mfc辦法就是將你的類置於mfc繼承體系之中,並使用相對應的巨集,如下所示:
#include
class animal : public cobject
;class dog : public animal
;class cat : public animal
;class cfoo
;int main(int argc, char* argv)
implement_dynamic(animal, cobject)
implement_dynamic(dog, animal)
implement_dynamic(cat, animal)
void cfoo::animalsays(animal* panimal)
另一種方法:rtti
c++內建的執行時型別檢查機制為rtti(run-time type information),rtti允許使用兩個操作符:typeid與dynamic_cast。用rtti解決上述問題的第一種方法是使用typeid,它返回乙個對type_info物件的引用,其儲存了傳遞進來的物件型別資訊。
#include
class animal ;};
class dog : public animal{};
class cat : public animal{};
class cfoo
;int main(int argc, char* argv)
void cfoo::animalsays(animal* panimal)
第二種方法是使用dynamic_cast,如果你傳遞給它乙個所不期望型別的指標,它將返回0,程式如下面這樣:
void cfoo::animalsays(animal* panimal)
注意,類animal至少必須有乙個虛函式。為什麼?因為如果你的類不是「多種型別」的,rtti機制不會正常工作。另外,rtti需從「專案設定——屬性」中開啟,預設是關閉的。譯者注:visual c++ 2008 sp1中在「專案屬性——配置屬性——c/c++——語言」下,預設是開啟的。
最後,真的需要它嗎?
乙個設計良好、用於多型的類,是無須擔心執行時型別檢查的,在本文這個特例中,可在抽象基類(animal)中放置乙個純虛函式isay,並為每個派生者新增一些具體的實現。
#include
class animal
;class dog : public animal
};class cat : public animal
};class cfoo
;int main(int argc, char* argv)
void cfoo::animalsays(animal* panimal)
看一下cfoo::animalsays函式,它非常清爽、簡潔,無需執行時型別檢查。
結論既可用rtti,也可用像mfc機制的方法來實現執行時型別檢查,但恐怕也沒什麼必要。
執行時型別檢查
執行時型別資訊 run time type information 通常記做rtti。在c primer第五版中,譯作執行型別識別 run time type identification 執行時型別資訊包括三部分 1 乙個運算子dynamic cast,給它乙個指向某某物件的基類指標,它能得到乙個...
RTTI 執行時型別檢查 虛函式
在c 層面主要體現在dynamic cast和typeid,vs中虛函式表的 1位置存放了指向type info的指標。對於存在虛函式的型別,typeid和dynamic cast都會去查詢type info rtti即執行時型別識別,用來識別動態物件的型別。即使我們僅僅有基類的指標和引用,可以識別...
C 關鍵字typeid 執行時型別檢查
在揭開typeid神秘面紗之前,我們先來了解一下 rtti run time type identification,執行時型別識別 它使程式能夠獲取由基指標或引用所指向的物件的實際派生型別,即允許 用指向基類的指標或引用來操作物件 的程式能夠獲取到 這些指標或引用所指物件 的實際派生型別。在c 中...