在C++這種可以進行多型機制的語言中,您可以將基底類別指標指向衍生類別物件,這種指定通常在執行時期後發生,您並無法在編譯時期即得知指標所指向的物
件型態,而必須在執行時期取得物件的執行時期資訊。
RTTI 全名為Run-Time Type Information,也有人作Run-Time Type
Identification,C++中用來取得指標或參考所實際代表的物件,您可以使用typeid()來取得物件於執行時期的資訊,要使用
typeid(),您必須包括<typeinfo>標頭檔,typeid()使用時傳入一個物件:
typeid(object);
typeid()會傳回一個type_info物件,其擁有幾個成員可以描述或進行物件的比較:
const
char *name(); // 取得物件型態名稱
bool
before(const type_info &ob); //
當物件的名稱順序位於ob之前時,傳回true
bool
operator==(const type_info &ob); // 比較物件型態是否相同
bool
operator!=(const type_info &ob); // 比較物件型態是否不同
==與!=運算子在這邊被重載為可以比較兩個物件的型態是否相同;typeid()也可以使用型態名稱作為引數,這通常是用來取得一個type-info
物件,並與一個物件作比較時使用:
typeid(type-name);
用範例來說明typeid()與其成員的使用方法與應用,下面這個程式只是使用name()取得物件的型態名稱:
#include <iostream> #include <typeinfo> using namespace std;
class Base { public: virtual void foo() { cout << "Base" << endl; } };
class Derived1 : public Base { public: void foo() { cout << "Derived1" << endl; } };
class Derived2 : public Base { public: void foo() { cout << "Derived2" << endl; } };
int main() { Base *ptr; // 基底類別指標 Base base; Derived1 derived1; Derived2 derived2;
ptr = &base; cout << "ptr 指向 " << typeid(*ptr).name() << endl;
ptr = &derived1; cout << "ptr 指向 " << typeid(*ptr).name() << endl;
ptr = &derived2; cout << "ptr 指向 " << typeid(*ptr).name() << endl; return 0; }
執行結果:
ptr 指向 4Base
ptr 指向 8Derived1
ptr 指向 8Derived2
|
您使用共同的基底類別指標來指向基底類別物件與衍生類別物件,雖然如此,還是利用typeid()取回的type-info物件仍可以得知物件的型態名
稱。
RTTI的使用時機之一,就是當您將物件以參考方式傳遞給函式時,函式的參數使用共同的基底類別指標或參考,但在函式中有必須操作衍生類別中的某個方法,
由於函式事先並不知道您傳入的物件型態名稱,所以您必須利用RTTI來進行判斷,下面的程式是個簡單的例子:
#include <iostream> #include <typeinfo> using namespace std;
class Base { public: virtual void foo() = 0; };
class Derived1 : public Base { public: void foo() { cout << "Derived1" << endl; } void showOne() { cout << "Yes! It's Derived1." << endl; } };
class Derived2 : public Base { public: void foo() { cout << "Derived2" << endl; } void showTwo() { cout << "Yes! It's Derived2." << endl; } };
void showWho(Base *base) { base->foo(); if(typeid(*base) == typeid(Derived1)) { Derived1 *derived1 = static_cast<Derived1*>(base); derived1->showOne(); } else if(typeid(*base) == typeid(Derived2)) { Derived2 *derived2 = static_cast<Derived2*>(base); derived2->showTwo(); } }
int main() { Derived1 derived1; Derived2 derived2;
showWho(&derived1); showWho(&derived2); return 0; }
執行結果:
Derived1
Yes! It's Derived1.
Derived2
Yes! It's Derived2.
|
傳統的C風格轉型語法也是可以使用的,例如:
Derived1
*derived1 = (Derived1*) base;
當然不建議使用這種方式強制轉型,事實上使用static_cast也不是很適合,C++為了支援RTTI還提供有dynamic_cast,這在下一個
主題中介紹。
|