執行期型態訊息
在程式設計中,所謂的執行期型態訊息(Runtime type information,RTTI)指的是在程式執行時儲存其物件的型態訊息的行為。某些語言實作僅保留有限的型態訊息,例如繼承樹資訊,而某些實作會保留較多資訊,例如物件的屬性及方法訊息。
執行期型態訊息是一個電腦術語,用以標示一個電腦語言是否有能力在執行期保持或判別其物件或變數的型態訊息。
C++
雖然執行期型態訊息是一個通用的電腦術語,但是通常用來稱呼C++的特質。為了讓C++的指令達到動態指派(dynamic_cast
)、型態識別碼(typeid
)操作與例外處理的能力,執行期型態訊息是必須的。
C++語言提供了dynamic_cast和typeid兩種運算子,typeid用於在執行期辨識型態訊息,dynamic_cast具有執行期型態辨識和型態轉換匹配2個功能。實現方法為每個型態對應一個const type_info型態對象,儲存了這個確切型態訊息。在C++標準標頭檔<typeinfo>
中,type_info類多載了operator=()、operator!=()、name()等成員函式。
dynamic_cast的語法形如:
dynamic_cast<dest>(src);
dest和src都必須為指標或者參照。如果執行期src和dest所參照的對象,是相同型態,或者存在is-a關係(public繼承),則轉換成功;否則轉換失敗。dynamic_cast只能用來轉換多型型態(即定義了虛擬函式)的對象的指標或參照。如果運算元是指標,成功則返回目標型態的指標,失敗返回NULL。如果運算元是參照,成功則返回目標型態的參照,失敗丟擲std::bad_cast異常。
dynamic_cast的「執行期型態的轉換匹配」,是通過維護一棵由type_info型態對象作為節點的型態繼承關係的樹,遍歷這棵繼承樹來確定一個待轉換的對象的型態和目標型態之間是否存在is-a關係。
下列是一C++的執行期型態訊息應用範例:
class base {
virtual ~base(){}
};
class derived : public base {
public:
virtual ~derived(){}
int compare (derived &ref);
};
int my_comparison_method_for_generic_sort (base &ref1, base &ref2)
{
derived & d = dynamic_cast<derived &>(ref1); // rtti used here
// rtti enables the process to throw a bad_cast exception
// if the cast is not successful
return d.compare (dynamic_cast<derived &>(ref2));
}
Visual C++
在類的虛表的前面存放RTTI資料塊的指標。因此,類必須有虛擬函式,才會有RTTI。 資料結構如下:
struct TypeDescriptor
{
DWORD ptrToVTable;
DWORD spare;
char name[8];
};
struct PMD
{
int mdisp; //member displacement
int pdisp; //vbtable displacement
int vdisp; //displacement inside vbtable
};
struct RTTIBaseClassDescriptor
{
struct TypeDescriptor* pTypeDescriptor; //type descriptor of the class
DWORD numContainedBases; //number of nested classes following in the Base Class Array
struct PMD where; //pointer-to-member displacement info
DWORD attributes; //flags, usually 0
};
struct RTTIClassHierarchyDescriptor
{
DWORD signature; //always zero?
DWORD attributes; //bit 0 set = multiple inheritance, bit 1 set = virtual inheritance
DWORD numBaseClasses; //number of classes in pBaseClassArray
struct RTTIBaseClassArray* pBaseClassArray;
};
struct RTTICompleteObjectLocator
{
DWORD signature; //always zero ?
DWORD offset; //offset of this vtable in the complete class
DWORD cdOffset; //constructor displacement offset
struct TypeDescriptor* pTypeDescriptor; //TypeDescriptor of the complete class
struct RTTIClassHierarchyDescriptor* pClassDescriptor; //describes inheritance hierarchy
};