RTTI(Run-Time Type Identification,運行時類型識別) 允許程序在運行階段通過基類指針或引用,查詢其實際指向的派生類型。這是 C++ 為支援多態而引入的關鍵機制——因為靜態類型(指針聲明類型)與動態類型(對象實際類型)可能不一致。
C++ 是強靜態類型語言,類型在編譯期確定。但多態要求基類指針指向派生對象,導致「靜態類型 ≠ 動態類型」。當需要根據實際類型執行不同邏輯(如向下轉型、類型查詢)時,編譯期無法決斷,必須引入 RTTI。
對比 Java:Java 通過反射機制與 instanceof 關鍵字原生支持運行時類型查詢,字節碼攜帶完整類型信息;C++ 則依賴編譯器生成的類型信息表(通常存放於虛表附近),僅當類包含虛函數時才啟用 RTTI。
typeid 運算符<typeinfo>const std::type_info&,描述表達式的動態類型name()(實現定義的類型名)、hash_code()(C++11)、before()(排序用)type_info 拷貝構造/賦值為 private/=delete,只能通過 typeid 獲取
#include
#include
class Base { virtual ~Base() = default; };
class Derived : public Base {};
int main() {
Base* ptr = new Derived();
std::cout << typeid(*ptr).name() << '\n'; // 輸出類似 "7Derived"(實現相關)
std::cout << (typeid(*ptr) == typeid(Derived)) << '\n'; // 1
delete ptr;
}
dynamic_cast 運算符nullptrstd::bad_cast
Base* pb = new Derived();
if (auto pd = dynamic_cast(pb)) {
pd->derivedOnlyMethod(); // 安全訪問派生類特有成員
} else {
// 轉換失敗處理
}
// 引用版本需配合 try-catch
try {
Derived& rd = dynamic_cast(*pb);
} catch (const std::bad_cast&) { /* ... */ }
編譯器在類佈局中嵌入類型信息(通常在虛表首部指向 type_info),dynamic_cast 通過遍歷繼承圖、比較類型信息完成合法性驗證。這帶來微小運行時開銷,換取類型安全。
type_info 內部結構剖析(以 MSVC 為例)簡化後的關鍵結構:
class type_info {
public:
virtual ~type_info();
bool operator==(const type_info&) const;
bool operator!=(const type_info&) const;
bool before(const type_info&) const; // 用於有序容器排序
const char* name() const; // 類型名(經過 name mangling)
const char* raw_name() const; // 內部編碼名
private:
void* _m_data;
char _m_d_name[1]; // 可變長度存儲名稱
type_info(const type_info&) = delete;
type_info& operator=(const type_info&) = delete;
};
因構造/賦值被刪除,用戶無法直接構造 type_info,只能通過 typeid 獲取引用。typeid 可能被實現為 type_info 的友元函數,從而能訪問私有構造函數創建對象並返回引用。
class A { virtual void f() {} };
class B : public A { void f() override {} };
class C : public B { void f() override {} };
class D : public A { void f() override {} };
int main() {
A* pa = new C();
B* pb = dynamic_cast(pa); // 成功:C 是 B 的派生
C* pc = dynamic_cast(pa); // 成功:精確匹配
D* pd = dynamic_cast(pa); // 失敗:返回 nullptr
std::cout << typeid(*pa).name() << '\n'; // "1C"
std::cout << (typeid(*pa) == typeid(C)) << '\n'; // true
}
| 操作符 | 用途 | 運行時檢查 |
|---|---|---|
static_cast | 編譯期可確定的相關類型轉換(含向下轉型,不安全) | 無 |
reinterpret_cast | 底層位模式重新解釋(極度危險) | 無 |
const_cast | 移除/添加 const/volatile | 無 |
dynamic_cast | 多態層級安全向下/橫向轉型 | 有(RTTI) |
dynamic_cast:如插件系統、異構容器處理,配合指針版本 + if 判斷。typeid 適合日誌、調試、序列化:獲取類型名稱用於輸出或註冊。-fno-rtti(GCC/Clang)或 /GR-(MSVC),但將無法使用 dynamic_cast 及 typeid 多態功能。RTTI 是 C++ 多態機制的補完,賦予靜態類型語言有限的動態反射能力。理解其底層實現(虛表、類型信息表)、性能代價與適用邊界,能幫助你在「純多態」與「類型查詢」之間做出恰當架構決策。