c語言強制類型轉換主要用於基礎的數據類型間的轉換,語法爲:html
(type-id)expression//轉換格式1 type-id(expression)//轉換格式2
c++除了能使用c語言的強制類型轉換外,還新增了四種強制類型轉換:static_cast、dynamic_cast、const_cast、reinterpret_cast,主要運用於繼承關係類間的強制轉化,語法爲:ios
static_cast<new_type> (expression) dynamic_cast<new_type> (expression) const_cast<new_type> (expression) reinterpret_cast<new_type> (expression)
備註:new_type爲目標數據類型,expression爲原始數據類型變量或者表達式。c++
《Effective C++》中將c語言強制類型轉換稱爲舊式轉型,c++強制類型轉換稱爲新式轉型。express
char a = 'a'; int b = static_cast<char>(a);//正確,將char型數據轉換成int型數據 double *c = new double; void *d = static_cast<void*>(c);//正確,將double指針轉換成void指針 int e = 10; const int f = static_cast<const int>(e);//正確,將int型數據轉換成const int型數據 const int g = 20; int *h = static_cast<int*>(&g);//編譯錯誤,static_cast不能轉換掉g的const屬性
if(Derived *dp = static_cast<Derived *>(bp)){//下行轉換是不安全的 //使用dp指向的Derived對象 } else{ //使用bp指向的Base對象 } if(Base*bp = static_cast<Derived *>(dp)){//上行轉換是安全的 //使用bp指向的Derived對象 } else{ //使用dp指向的Base對象 }
dynamic_cast<type*>(e) dynamic_cast<type&>(e) dynamic_cast<type&&>(e)
type必須是一個類類型,在第一種形式中,type必須是一個有效的指針,在第二種形式中,type必須是一個左值,在第三種形式中,type必須是一個右值。在上面全部形式中,e的類型必須符合如下三個條件中的任何一個:e的類型是是目標類型type的公有派生類、e的類型是目標type的共有基類或者e的類型就是目標type的的類型。若是一條dynamic_cast語句的轉換目標是指針類型而且失敗了,則結果爲0。若是轉換目標是引用類型而且失敗了,則dynamic_cast運算符將拋出一個std::bad_cast異常(該異常定義在typeinfo標準庫頭文件中)。e也能夠是一個空指針,結果是所需類型的空指針。安全
if(Derived *dp = dynamic_cast<Derived *>(bp)){ //使用dp指向的Derived對象 } else{ //使用bp指向的Base對象 }
值得注意的是,在上述代碼中,if語句中定義了dp,這樣作的好處是能夠在一個操做中同時完成類型轉換和條件檢查兩項任務。jsp
(2)引用類型編輯器
由於不存在所謂空引用,因此引用類型的dynamic_cast轉換與指針類型不一樣,在引用轉換失敗時,會拋出std::bad_cast異常,該異常定義在頭文件typeinfo中。函數
void f(const Base &b){ try{ const Derived &d = dynamic_cast<const Base &>(b); //使用b引用的Derived對象 } catch(std::bad_cast){ //處理類型轉換失敗的狀況 } }
const_cast,用於修改類型的const或volatile屬性。 性能
const int g = 20; int *h = const_cast<int*>(&g);//去掉const常量const屬性 const int g = 20; int &h = const_cast<int &>(g);//去掉const引用const屬性 const char *g = "hello"; char *h = const_cast<char *>(g);//去掉const指針const屬性
new_type必須是一個指針、引用、算術類型、函數指針或者成員指針。它能夠把一個指針轉換成一個整數,也能夠把一個整數轉換成一個指針(先把一個指針轉換成一個整數,再把該整數轉換成原類型的指針,還能夠獲得原先的指針值)。spa
reinterpret_cast意圖執行低級轉型,實際動做(及結果)可能取決於編輯器,這也就表示它不可移植。
舉一個錯誤使用reintepret_cast例子,將整數類型轉換成函數指針後,vc++在執行過程當中會報"...中的 0xxxxxxxxx 處有未經處理的異常: 0xC0000005: Access violation"錯誤:
#include <iostream> using namespace std; int output(int p){ cout << p <<endl;
return 0; } typedef int (*test_func)(int );//定義函數指針test_func int main(){ int p = 10; test_func fun1 = output; fun1(p);//正確 test_func fun2 = reinterpret_cast<test_func>(&p); fun2(p);//...處有未經處理的異常: 0xC0000005: Access violation return 0; }
IBM的C++指南、C++之父Bjarne Stroustrup的FAQ網頁和MSDN的Visual C++也都指出:錯誤的使用reinterpret_cast很容易致使程序的不安全,只有將轉換後的類型值轉換回到其原始類型,這樣纔是正確使用reinterpret_cast方式。
// expre_reinterpret_cast_Operator.cpp // compile with: /EHsc #include <iostream> // Returns a hash code based on an address unsigned short Hash( void *p ) { unsigned int val = reinterpret_cast<unsigned int>( p ); return ( unsigned short )( val ^ (val >> 16)); } using namespace std; int main() { int a[20]; for ( int i = 0; i < 20; i++ ) cout << Hash( a + i ) << endl; }
class A { public: int m_a; }; class B { public: int m_b; }; class C : public A, public B {};
C c; printf("%p, %p, %p", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));
參考資料:
a):http://en.cppreference.com/w/cpp/language/static_cast
b):http://en.cppreference.com/w/cpp/language/dynamic_cast
c):http://en.cppreference.com/w/cpp/language/const_cast
d):http://en.cppreference.com/w/cpp/language/reinterpret_cast
e):《Effective C++》條款27:儘可能少作轉型動做
f): 百度百科
g) 《C++ Primer》