運行時類型識別(RTTI)

實現RTTI的兩個重要運算符:
typeid:返回表達式的類型。
dynamic_cast:用於將基類的指針或引用安全地轉換成派生類的指針或引用。
當我們將這兩個運算符用於某種類型的指針或引用,並且該類型含有虛函數時,運算符將使用指針或者引用所綁定對象的動態類型。




特別適用於此情況:我們想使用基類對象的指針或引用執行某個派生類操作並且該操作不是虛函數。

1.dynamic_cast:比如含有虛函數的基類B和從基類B派生出的派生類D,則B *pb; D *pd, d; pb=&d; pd=dynamic_cast<D*>(pb); 最後一條語句表示把指向派生類D的基類指針pb轉換爲派生類D的指針,然後將這個指針賦給派生類D的指針pd,有人可能會覺得這樣做沒有意義,既然指針pd要指向派生類爲什麼不pd=&d;這樣做更直接呢?因爲虛函數的基類版本和派生類版本必須具有相同的形參類型。就是當在派生類中覆蓋虛函數時,若參數有基類指針或引用,需在函數裏將參數強制轉換爲派生類指針或引用。也即有些時候我們需要強制轉換,比如如果指向派生類的基類指針B想訪問派生類D中的除虛函數之外的成員時就需要把該指針轉換爲指向派生類D的指針,以達到訪問派生類D中特有的成員的目的,比如派生類D中含有特有的成員函數g(),這時可以這樣來訪問該成員dynamic_cast<D*>(pb)->g();因爲dynamic_cast轉換後的結果是一個指向派生類的指針,所以可以這樣訪問派生類中特有的成員。但是該語句不影響原來的指針的類型,即基類指針pb仍然是指向基類B的。如果單獨使用該指針仍然不能訪問派生類中特有的成員。

2.typeid:先判斷對象類型,才能確保dynamic_cast進行安全轉換。



<strong>//例:比如我們有兩個變量,它們可能是基類對象也可能是派生類對象。我們要比較它們是否相等要怎麼做?首先,我們必須用typeid看這兩個對象是否同類型!然後纔對它們的每個屬性進行比較(這又涉及到另一個問題:虛函數的基類版本和派生類版本必須具有相同的形參類型。如果我們想定義一個虛函數equal,則該函數的形參必須是基類的指針或引用。此時,equal函數將只能使用基類的成員,而不能比較派生類獨有的成員。當在派生類中覆蓋equal時會出現這個問題)!</strong>
class Base
{
	friend bool operator==(const Base&,const Base&);
public:
	//Base的接口成員
protected:
	virtual bool equal(const Base&)const;
	//Base的數據成員和其他用於是實現的成員
};


class Derived:public Base
{
public:
	//Derived的其他接口成員
protected:
	bool equal(const Base&)const;			//需強制轉換,否則無法比較Derived的特有成員!
	//Derived的數據成員和其他用於實現的成員
};


bool operator==(const Base &lhs,const Base &rhs)
{
	//如果typeid不相同,返回false;否則虛調用equal
	return typeid(lhs)==typeid(rhs)&&lhs.equal(rhs);	//動態綁定!
}


bool Derived::equal(const Base &rhs)const
{
	//我們清楚這兩個類型是相等的,所以轉換過程不會拋出異常
	auto r=dynamic_cast<const Derived&>(rhs);	//在派生類中覆蓋equal,需強制轉換,因爲基類引用是無法取得派生類的特有成員的!
	//執行比較兩個Derived對象的操作並返回結果
}


bool Base::equal(const Base &rhs)const
{
	//執行比較Base對象的操作
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章