C++運行時動態類型


RTTI

運行時類型識別(RTTI)的引入有三個作用:

  1. 配合typeid操作符的實現;
  2. 實現異常處理中catch的匹配過程;
  3. 實現動態類型轉換dynamic_cast

typeid操作符的實現

靜態類型

C++中支持使用typeid關鍵字獲取對象類型信息,它的返回值類型是const std::type_info&,例

#include <typeinfo>
#include <cassert>
struct B {} b, c;
struct D : B {} d;
void test() {
    const std::type_info& tb = typeid(b); 
    const std::type_info& tc = typeid(c); 
    const std::type_info& td = typeid(d);
    assert(tb == tc);   // b和c具有相同的類型
    assert(&tb == &tc); // tb和tc引用的是相同的對象
    assert(tb != td);   // 雖然D是B的子類,但是b和d的類型卻不同
    assert(&tb != &td); // tb和td引用的是不同的對象
}

動態類型

當typeid的操作數引用的是一個動態類(含有虛函數的類) 類型時,它的返回值是被引用對象對應類型的const std::type_info&,例:

#include <typeinfo>
#include <cassert>
struct B { virtual void foo() {} };
struct C { virtual void bar() {} };
struct D : B, C {};
void test() {
    D d;
    B& rb = d;
    C& rc = d;
    assert(typeid(rb) == typeid(d));  // rb引用的類型與d相同
    assert(typeid(rb) == typeid(rc)); // rb引用的類型與rc引用的類型相同
}

編譯時可能還不知道rb或rc引用的類型,運行時怎么能判斷該返回基類還是派生類對應的類型信息對象呢?

首先我們看看虛表的結構,在虛函數指針前面有RTTI信息。

image

如果是含有虛函數,運行時便可以通過vptr找到“虛函數表”,而“虛函數表”之前的一個位置存放了需要的類型信息對象,typeid可以直接返回這里的類型信息對象引用即可。

image

實現異常處理中catch的匹配過程

catch的匹配過程也可利用與typeid相似的原理進行類型匹配判斷,此不再贅述。

動態類型轉換(dynamic_cast)

先上一個例子:

image

type_info對象里面會有整個繼承體系的信息(通過指針),因此繼承關系可以通過此樹狀結構判斷,有了繼承關系,再遞歸從虛表中查找基類子對象在派生類中的偏移值,便可以確定最終返回地址。

image

  • '# 4例子:
    通過pa找到_D的type_info,對比和C的type_info的不同,但是在type_info的指針里面找到C的type_info。加上C的type_info的通過偏移量,返回指針結果
  • '# 2例子:
    通過pa找到D的type_info,和目標D的type_info相同,直接加上偏移量,返回指針

參考文獻

C/C++雜記:運行時類型識別(RTTI)與動態類型轉換原理


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM