前言
rtti是」runtime type information」的縮寫,意思是執行時型別資訊,它提供了執行時確定物件型別的方法。rtti並不是什麼新的東西,很早就有了這個技術,但是,在實際應用中使用的比較少而已。而我這裡就是對rtti進行總結,今天我沒有用到,並不代表這個東西沒用。學無止境,先從typeid函式開始講起。
typeid函式
typeid的主要作用就是讓使用者知道當前的變數是什麼型別的,比如以下**:
複製** **如下:
#include
#include
using namespace std;
int main()
對於c++支援的內建型別,typeid能完全支援,我們通過呼叫typeid函式,我們就能知道變數的資訊。對於我們自定義的結構體,類呢?
複製** **如下:
#include
#include
using namespace std;
class a;
class b : public a;
struct c;
int main()
是的,對於我們自定義的結構體和類,tpyeid都能支援。在上面的**中,在呼叫完typeid之後,都會接著呼叫name()函式,可以看出typeid函式返回的是乙個結構體或者類,然後,再呼叫這個返回的結構體或類的name成員函式;其實,typeid是乙個返回型別為type_info型別的函式。那麼,我們就有必要對這個type_info類進行總結一下,畢竟它實際上存放著型別資訊。
type_info類
去掉那些該死的巨集,在visual studio 2012中檢視type_info類的定義如下:
複製** **如下:
class type_info
;在type_info類中,複製建構函式和賦值運算子都是私有的,同時也沒有預設的建構函式;所以,我們沒有辦法建立type_info類的變數,例如type_info a;這樣是錯誤的。那麼typeid函式是如何返回乙個type_info類的物件的引用的呢?我在這裡不進行討論,思路就是類的友元函式。
typeid函式的使用
typeid使用起來是非常簡單的,常用的方式有以下兩種:
1.使用type_info類中的name()函式返回物件的型別名稱
就像上面的**中使用的那樣;但是,這裡有一點需要注意,比如有以下**:
複製** **如下:
#include
#include
using namespace std;
class a;
class b : public a;
int main()
我使用了兩次typeid,但是兩次的引數是不一樣的;輸出結果也是不一樣的;當我指定為pa時,由於pa是乙個a型別的指標,所以輸出就為class a *;當我指定*pa時,它表示的是pa所指向的物件的型別,所以輸出的是class a;所以需要區分typeid(*pa)和typeid(pa)的區別,它們兩個不是同乙個東西;但是,這裡又有問題了,明明pa實際指向的是b,為什麼得到的卻是class a呢?我們在看下一段**:
複製** **如下:
#include
#include
using namespace std;
class a;
class b : public a;
int main()
好了,我將print函式變成了虛函式,輸出結果就不一樣了,這說明什麼?這就是rtti在搗鬼了,當類中不存在虛函式時,typeid是編譯時期的事情,也就是靜態型別,就如上面的cout《程式設計中,經常會出錯,一定要謹記。
2.使用type_info類中過載的==和!=比較兩個物件的型別是否相等
這個會經常用到,通常用於比較兩個帶有虛函式的類的物件是否相等,例如以下**:
複製** **如下:
#include
#include
using namespace std;
class a;
class b : public a;
class c : public a;
void handle(a *a)
else if (typeid(*a) == typeid(b))
else if (typeid(*a) == typeid(c))
&npgbvebsp; else
} int main()
這是一種用法,呆會我再總結如何使用dynamic_cast來實現同樣的功能。
dynamic_cast的內幕
在這篇《static_cast、dynamic_cast、const_cast和reinterpret_cast總結》的文章中,也介紹了dynamic_cast的使用,對於dynamic_cast到底是如何實現的,並沒有進行說明,而這裡就要對於dynamic_cast的內幕一**竟。首先來看一段**:
複製** **如下:
#inclwww.cppcns.comude
#include
using namespace std;
class a;
class b;
class c : public a, public b;
int main()
delete pa;
}在上面**中,如果我們直接將pa賦值給pc,這樣編譯器就會提示錯誤,而當我們加上了dynamic_cast之後,一切就ok了。那麼dynamic_cast在後面幹了什麼呢?
dynamic_cast主要用於在多型的時候,它允許在執行時刻進行型別轉換,從而使程式能夠在乙個類層次結構中安全地轉換型別,把基類指標(引用)轉換為派生類指標(引用)。我在《com程式設計——介面的背後》這篇博文中總結的那樣,當類中存在虛函式時,編譯器就會在類的成員變數中新增乙個指向虛函式表的vptr指標,每乙個class所關聯的type_info object也經由virtual table被指出來,通常這個type_info object放在**的第乙個slot。當我們進行dynamic_cast時,編譯器會幫我們進行語法檢查。如果指標的靜態型別和目標型別相同,那麼就什麼事情都不做;否則,首先對指標進行調整,使得它指向vftable,並將其和調整之後的指標、調整的偏移量、靜態型別以及目標型別傳遞給內部函式。其中最後乙個引數指明轉換的是指標還是引用。兩者唯一的區別是,如果轉換失敗,前者返回null,後者丟擲bad_cast異常。對於在typeid函式的使用中所示例的程式,我使用dynamic_cast進行更改,**如下:
複製** **如下:
#include
#include
using namespace std;
class a;
class b : public a;
class c : public a;
void handle(a *a)
else if (dynamic_cast(a))
else
} int main()
這個是使用dynamic_cast進行改寫的版本。實際專案中,這種方法會使用的更多點。
總結本文標題: c++中的rtti機制詳解
本文位址:
C 中的RTTI機制詳解
前言 rtti是 runtime type information 的縮寫,意思是執行時型別資訊,它提供了執行時確定物件型別的方法。rtti並不是什麼新的東西,很早就有了這個技術,但是,在實際應用中使用的比較少而已。而我這裡就是對rtti進行總結,今天我沒有用到,並不代表這個東西沒用。學無止境,先從...
RTTI機制詳解
引子 以前我們 過,rtti的訪問和虛表相關,並且rtti基本上是為了dynamic cast 和typeid以及異常而實現的。今天我們詳細 下異常的實現機制。c abi中的rtti 通過c 程式語言的定義,我們知道型別資訊在用於以下三個目的時,可以在執行時獲得 a.為了支援typeid運算子 b....
C 的 RTTI 可以刪掉了
一兩年沒碰程式設計了,最近開始寫乙個程式,寫的過程中想到了一些東西。看這段 這個乙個用模板實現的協議類,擁有乙個虛成員函式和乙個虛析構函式,其功能可以用以下 來測試 和協議類有點不同,這裡的模板協議類語義上並不是指標,是不是省心很多?有了新標準的move語意的話,效能上也不會有什麼問題。這只是個很簡...