C++類型轉換(翻譯自cplusplus)
前言
原文翻譯自http://www.cplusplus.com/doc/tutorial/typecasting/,覺得這篇文章講C++類型轉換簡單明了,所以特別翻譯了下。
在C++中,將一個已知的類型轉換為另一個類型,我們稱呼為類型轉換,本文會介紹C++的各種類型轉換。
隱式轉換
隱式轉換不需要任何操作符,它們會自動執行,當值被賦值到兼容類型,就會執行,例如:
short a=2000;int b; b=a;
隱式轉換,也包括構造函數和運算符的轉換,例如:
class A {};class B { public: B (A a) {} }; A a; B b=a;
顯式轉換
C++是一個強類型的語言。許多轉換,需要顯式轉換,例如
short a=2000;int b; b = (int) a; // c-like cast notation b = int (a); // functional notation
上述的類型轉換已經滿足了基本類型的轉換了,但是如果應用于類和指針中,代碼可以編譯,但是在運行過程中會出錯。例如
// class type-casting #include <iostream>using namespace std;class CDummy { float i,j; };class CAddition { int x,y; public: CAddition (int a, int b) { x=a; y=b; } int result() { return x+y;} };int main () { CDummy d; CAddition * padd; padd = (CAddition*) &d; cout << padd->result(); return 0; }
這段代碼會在運行期出錯,在執行padd->result()時異常退出。
傳統明確的類型轉換,可以轉換成任何其他指針類型任何指針,它們指向的類型無關。在隨后的調用成員的結果,會產生一個運行時錯誤或意外的結果。
C++標準轉換運算符
傳統的類和指針的類型轉換,十分不安全,可能會在運行時,由于類型不匹配異常退出,所以C++提供了四個標準轉換運算符:dynamic_cast, reinterpret_cast, static_cast, const_cast
dynamic_cast <new_type> (expression) reinterpret_cast <new_type> (expression) static_cast <new_type> (expression) const_cast <new_type> (expression)
dynamic_cast
dynamic_cast只能用于指針和引用的對象。其目的是確保類型轉換的結果是一個有效的完成所請求的類的對象,所以當我們從一個類轉換到這個類的基類,dynamic_cast總是可以成功
class CBase { };class CDerived: public CBase { }; CBase b; CBase* pb; CDerived d; CDerived* pd; pb = dynamic_cast<CBase*>(&d); // ok: derived-to-base pd = dynamic_cast<CDerived*>(&b); // wrong: base-to-derived
當新的類型不是被轉換的類型的基類,dynamic_cast無法完成指針的轉換,返回NULL,如果dynamic_cast是用來轉換為引用類型的轉換失敗,會拋出"Bad_cast exception"異常。
dynamic_cast 可以轉換NULL指針為不相關的類,也可以任何類型的指針為void指針。
dynamic_cast的需要的運行時類型信息(RTTI),保持動態類型跟蹤。一些編譯器支持此功能默認情況下是禁用的選項。這必須啟用運行時類型檢查,使用dynamic_cast的正常工作。
static_cast
static_cast可以執行相關的類的指針之間的轉換,不僅從派生類到基類的轉換,也可以做到基類到派生類的轉換。static_cast沒有在運行時進行安全檢查,因此,它是程序員,以確保轉換是安全的,但是dynamic_cast的類型安全檢查的開銷,static_cast是可以避免的。
class CBase {};class CDerived: public CBase {}; CBase * a = new CBase; CDerived * b = static_cast<CDerived*>(a);
上述代碼是合法的,雖然b指向一個不完整的對象,并可能在運行期導致錯誤。
static_cast也可以用來執行任何其他非指針的轉換,例如像基本類型之間的標準轉換,也可以是隱式執行
double d=3.14159265;int i = static_cast<int>(d);
reinterpret_cast
reinterpret_cast轉換成任何其他指針類型,甚至無關的類,任何指針類型。操作的結果是一個簡單的從一個指針到其他的值的二進制拷貝。所有的指針轉換是允許的:不管是指針指向的內容還是指針本身的類型。
同時,它也可以把指針轉換為整數,但是整數是平臺相關的,必須保證整數足夠大到可以包含指針本身的內容,最后再轉換為一個合法的指針。
class A {};class B {}; A * a = new A; B * b = reinterpret_cast<B*>(a)
const_cast
const_cast用于操縱對象的常量性,既要設置或刪除。例如,一個函數要求一個非const參數,而程序需要傳遞一個const參數。
#include <iostream>using namespace std;void print (char * str) { cout << str << endl; }int main () { const char * c = "sample text"; print ( const_cast<char *> (c) ); return 0; }
typeid
typeid的允許檢查表達式的類型
typeid (expression)
這個操作符返回一個引用在標準頭文件<typeinfo>中定義的常量對象,是一個類型的type_info。這個返回值可以與另一個使用運算符==和!=進行比較兩個數據類型或類的名稱,或者也可以使用其name() 成員函數獲得類型名字(一個0結束的的字符串)。
// typeid #include <iostream> #include <typeinfo>using namespace std;int main () { int * a,b; a=0; b=0; if (typeid(a) != typeid(b)) { cout << "a and b are of different types:\n"; cout << "a is: " << typeid(a).name() << '\n'; cout << "b is: " << typeid(b).name() << '\n'; } return 0; }
當typeid應用使用RTTI來跟蹤動態對象的類型,那么當typeid的是應用于表達式,其類型是一個多態類,其結果是派生的最完整的對象的類型:
// typeid, polymorphic class #include <iostream> #include <typeinfo> #include <exception>using namespace std;class CBase { virtual void f(){} };class CDerived : public CBase {};int main () { try { CBase* a = new CBase; CBase* b = new CDerived; cout << "a is: " << typeid(a).name() << '\n'; cout << "b is: " << typeid(b).name() << '\n'; cout << "*a is: " << typeid(*a).name() << '\n'; cout << "*b is: " << typeid(*b).name() << '\n'; } catch (exception& e) { cout << "Exception: " << e.what() << endl; } return 0; }
注意:返回的字符串成員的type_info名稱取決于你的編譯器和庫的具體實現,其典型的類型名稱,它不一定是一個簡單的字符串.
如果類型typeid的參數是引用操作符(*)開頭的指針,而且這個指針是NULL,typeid會拋出一個bad_typeid異常。
轉自:http://www.cnblogs.com/ggjucheng/archive/2012/01/04/2311650.html