C++ Primer第五版筆記——運行時類型識別

運行時類型識別(run-time type identification,RTTI)的功能由兩個運算符實現:
 typeid運算符,用於返回表達式的類型。
 dynamic_cast運算符,用於將基類的指針或引用安全的轉換成派生類的指針或引用。
 當這兩個運算符用於某種類型的指針或引用,並且該類型含有虛函數時,運算符將使用指針或引用所綁定的對象的動態類型。
 這兩個運算符適用於以下情況:使用基類對象的指針或引用執行某個派生類的操作並且該操作不是虛函數(在可能的情況下還是優先使用定義虛函數的方式)。


dynamic_cast運算符

使用形式:

dynamic_cast<type*>(e)
dynamic_cast<type&>(e)
dynamic_cast<type&&>(e)

其中type必須是一個類類型,並且通常情況下該類型應該有虛函數。第一個形式中,e必須是一個有效的指針;第二個形式中,e必須是一個左值;第三個形式中,e不能一個左值。
在上面的所有形式中,e的類型必須符合以下三個條件中的任何一個:
1、e的類型與type的類型相同;
2、e的類型與type的公有派生類的類型相同;
3、e的類型與type的公有基類的類型相同。
符合條件的情況下,類型轉換可以成功;否則會失敗。如果一條dynamic_cast語句的轉換目標是指針類型並且失敗了,則結果爲0;如果轉換目標是引用類型並且失敗了,則會拋出bad_cast異常。

指針類型的dynamic_cast
  假定Base類至少含有一個虛函數,Derived是Base的公有派生類。如果有一個Base的指針bp,則我們可以在運行時將它轉換成指向Derived的指針:

if(Derived* dp = dynamic_cast<Derived*>(bp)){
	//。。。
}else{
	//。。。
}

如果bp指向Derived對象,則上述類型轉換初始化dp並令其指向bp指向的Derived對象。類型轉換失敗的情況下,其結果爲0,dp爲0意味着if條件失敗。
(此處的dp是局部變量,這樣做的好處是可以在一條語句中完成類型轉換和條件檢查兩項任務,且dp在if外部不會被訪問到)。

引用類型的dynamic_cast
  引用類型的dynamic_cast與指針類型的dynamic_cast在表示錯誤發生的方式上略有不同。因爲不存在空引用,因此當對引用類型轉換失敗時,程序拋出一個名爲std::bad_cast的異常,該異常定義在typeinfo標準庫頭文件中。

void f(const Base& b){
	try{
		const Derived& d = dynamic_cast<const Derived&>(b);
		//。。。
	}catch(bad_cast){
	//。。。
	}
}

typeid運算符

該運算符允許程序向表達式提問:你的對象時什麼類型?其表達式形式如:typeid(e)。其中e可以是任意表達式或者類型的名字。其結果是一個常量對象的引用,該對象的類型是標準庫類型type_info或type_info的公有派生類型(該類定義在typeinfo頭文件)。

使用typeid運算符
  通常情況下,使用該運算符來比較兩個表達式的類型是否相同,或者比較一條表達式與指定類型是否相同:

Derived* dp = new Derived;
Base* bp = dp;						//兩個指針都指向Derived對象
//在運行時比較兩個對象的類型
if(typeid(*dp) == typeid(*bp)){
	//。。。
}
//檢查運行時類型是否和指定類型相同
if(typeid(*bp) == typeid(Derived)){
	//。。。
}

第一個if語句,比較bp和dp所指向的對象的動態類型是否相同,第二個if判斷bp指向的對象是否是Derived對象。

typeid是否需要運行時檢查決定了表達式是否會被求值,只有當類型含有虛函數時,編譯器纔會對表達式求值。反之,如果類型不含有虛函數,則typeid返回表達式的靜態類型(編譯器無需對表達式求值也能知道表達式的靜態類型)。


例子

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的數據成員和其他用於實現的成員
};

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 Deived&>(rhs);
	//。。。
}
bool Base::equal(const Base& rhs) const{
	//。。。
}


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