執行時型別檢查

2021-06-28 20:42:29 字數 3650 閱讀 1750

執行時型別資訊(run-time type information)通常記做rtti。

在c++primer第五版中,譯作執行型別識別(run-time type identification)。

執行時型別資訊包括三部分:

1)乙個運算子dynamic_cast,給它乙個指向某某物件的基類指標,它能得到乙個到這個物件的派生類指標。只有在被指物件確實屬於所指明的派生類時,運算子dynamic_cast才能返回乙個指標,否則就返回0;

2)乙個運算子typeid,它對乙個給定的基類指標識別出被指物件的確切型別。

3)乙個結構type_info,作為與有關型別的更多執行時型別資訊的掛接點(hook)

這個機制特別適用於    想使用基類物件的的指標或引用執行某個派生類的操作並且該操作不是虛函式    的時候。一般來說,能用虛函式就用虛函式。到操作被定義成虛函式時,編譯器將根據物件的動態型別自動的選擇正確的函式版本。

使用rtti的是時候必須清楚地知道轉換的目標型別並且必須檢查型別轉換是否被正確執行。

dynamic_cast運算子:

當我們想安全的使用派生類的某些細節時,為了使用這個派生類,我們需要獲得乙個指向派生類的指標。通常情況下,我們並不關心被指向物件的確鑿型別,我們只需要知道我們能不能安全地做這個強制。這時我們可以通過dynamic_cast運算子來實現。

例如:

#include class dialog

;class dialog_box : public dialog

virtual int ask() };

class dbox_w_str : public dialog_box

int ask()

virtual char *get_string() };

void my_func(dialog_box *bp)

else }

int main()

就一般而言,如果*p確實是乙個t或者由t派生的類的物件,在這裡的dynamic_cast(p)運算子就會將其運算物件轉換成所需要的t*型別;否則

dynamic_cast(p)將是0;特別的,我們可以將空指標強制到所需型別的空指標。

當然,我們也可以通過作用dynamic_cast運算子把物件強制到某個引用型別。如果強制失敗就會丟擲乙個bad_cast異常。

例如:void my_func(dialog_box &bp)

將測試和強制合併為乙個操作有很多優點:

1.    動態強制使測試和強制之間不會出現匹配錯誤。

2.    通過利用在物件裡的可用的型別資訊,我們可能將它轉換到這個強制的作用域裡看不到完整定義的某個型別。

3.    通過利用在物件裡可用的型別資訊,我們經常可以從乙個虛的基類強制到乙個派生類中去。

4.    靜態的強制不能對所有的這些情況都給出正確的結果。

typeid運算子和type_info類:

typeid運算子的出現主要是為了滿足下面兩個需求:

1)可能需要乙個確定物件的確切型別。也就是說,告訴程式設計師這個物件就是x類的物件,而不是說,它是x類的或者某個由x類派生的類的物件。dynamic_cast做的就是後一件事。

2)以乙個物件的確切型別作為過渡,得到描述該型別其他性質的資訊。

如果typeid()是乙個函式,那麼它的宣告大概是這個樣子的:

class type_info;

const type_info& typeid(type_name);    //pseudo declaration

const type_info& typeid(expression);    //pseudo declaration

也就是說,typeid()返回某個未知型別的引用。給它乙個type_name(型別名)作為引數,typeid()返回到乙個type_info的引用,該type_info表示這個type_name。給定乙個expression(表示式)作為引數,typeid()返回到乙個type_info引用,這個type_info表示expression所指向的型別。

type_info類type_info類在標準標頭檔案定義,如果想使用typeid()的結果,就需要包含這個標頭檔案。type_info類的確切定義是與實現有關的,但是它應該是乙個多型型別,提供比較和另外乙個操作,該操作返回所表示的型別名:

class type_info ;

函式before()是為了使type_info資訊能夠排序,以便能夠通過雜湊表的方式訪問它們。由befor()定義的順序和繼承關係之間沒有任何關係。進一步說,就是對不同程式或者同乙個程式的不同執行,我們都不能保證before()能產生同樣的結果。在這個方面,befroe()和取位址符類似。

我們無法定義或拷貝type_info型別的物件,也不能為type_info物件賦值。建立type_info物件的唯一途徑就是使用typeid運算子。

繼續說回typeid運算子。typeid運算子可以作用與任何表示式。如果表示式是乙個引用,則typeid返回該引用型別。不過當typeid作用於函式或陣列時,並不會執行指向指標的標準型別的轉換。也就是是說,如果我們隊陣列a執行typeid(a),則所獲得的結果是陣列型別而非指標型別。比如:

int a[10];

std::cout << typeid(a).name() << std::endl;

顯示的結果是 int  [10],說明a是乙個長度為10 的整型陣列。而不是返回乙個int *;這也說明了在c/c++裡面,陣列名和指標並不完全相等。

當運算物件不屬於類型別(比如內建型別)或者是乙個不包含任何虛函式的類時,typeid運算子指示的是運算物件的靜態型別。而當運算物件是定義了至少乙個虛函式的類的左值時,typeid的結果知道執行時才會求得。

typeid的使用例子:

#include class dialog

;class dialog_box : public dialog

virtual int ask() };

class dbox_w_str : public dialog_box

int ask()

virtual char *get_string() };

void my_func(dbox_w_str *bp1, dialog_box *bp2)

else }

int main()

當typeid作用於指標(而不是指標所指的物件的時候),返回的結果是該指標的靜態編譯時的型別。當且僅當類含有虛函式時,typeid的表示式才會被求值,否則typeid返回表示的靜態型別,編譯器無需對表示求值也能知道表示式的靜態型別。

修改上面的例子:

#include class dialog

;class dialog_box : public dialog

virtual int ask() };

class dbox_w_str : public dialog_box

int ask()

virtual char *get_string() };

void my_func(dbox_w_str *bp1, dialog_box *bp2)

else }

int main()

如果這個時候,dbp或者bp是乙個空指標的話,typeid就會丟擲乙個名為bad_typeid的異常。

C 中的執行時型別檢查

c 中的執行時型別檢查 簡介經常有人問到 我怎樣才能在執行時確定或檢查c 中物件的型別呢?下面通過乙個簡單問題來作一演示。以下程式會在第一次呼叫cfoo animalsays 時顯示 bark 而第二次呼叫時顯示 miaou class animal class dog public animal ...

RTTI 執行時型別檢查 虛函式

在c 層面主要體現在dynamic cast和typeid,vs中虛函式表的 1位置存放了指向type info的指標。對於存在虛函式的型別,typeid和dynamic cast都會去查詢type info rtti即執行時型別識別,用來識別動態物件的型別。即使我們僅僅有基類的指標和引用,可以識別...

執行時型別識別

執行時的型別識別 rtti 分為兩類 1.typeid操作符 2.dynamic cast操作符 先看第二種 dynamic cast完成將基類型別的指標或者引用安全轉化為派生類型別的指標和引用。對於指標,如果轉化失敗,則將指標置為null,對於引用型別,因為沒有null,所以直接丟擲bad cas...