C++四种强制类型转换 dynamic_cast,const_cast,static_cast,reinterpret_cast
dynamic_cast? 用于多態類型的轉換
static_cast?用于非多態類型的轉換
const_cast? 用于刪除?const、volatile?和?__unaligned?特性
reinterpret_cast?用于位的簡單重新解釋
static_cast
用法:static_cast < type-id > ( expression_r_r )
該運算符把expression_r_r轉換為type-id類型,但沒有運行時類型檢查來保證轉換的安全性。它主要有如下幾種用法:
用于類層次結構中基類和子類之間指針或引用的轉換。進行上行轉換(把子類的指針或引用轉換成基類表示)是安全的;進行下行轉換(把基類指針或引用轉換成子類表示)時,由于沒有動態類型檢查,所以是不安全的。
用于基本數據類型之間的轉換,如把int轉換成char,把int轉換成enum。這種轉換的安全性也要開發人員來保證。
把空指針轉換成目標類型的空指針。
把任何類型的表達式轉換成void類型。
注意:static_cast不能轉換掉expression_r_r的const、volitale、或者__unaligned屬性。
dynamic_cast
用法:dynamic_cast < type-id > ( expression_r_r )
該運算符把expression_r_r轉換成type-id類型的對象。Type-id必須是類的指針、類的引用或者void *;如果type-id是類指針類型,那么expression_r_r也必須是一個指針,如果type-id是一個引用,那么expression_r_r也必須是一個引用。
dynamic_cast主要用于類層次間的上行轉換和下行轉換,還可以用于類之間的交叉轉換。
在類層次間進行上行轉換時,dynamic_cast和static_cast的效果是一樣的;在進行下行轉換時,dynamic_cast具有類型檢查的功能,比static_cast更安全。
class B
{
public:
int m_iNum;
virtual void foo();
};
class D:public B
{
public:
? char *m_szName[100];
};
?
void func(B *pb)
{
? D *pd1 = static_cast<D *>(pb);
? D *pd2 = dynamic_cast<D *>(pb);
}
在上面的代碼段中,如果pb指向一個D類型的對象,pd1和pd2是一樣的,并且對這兩個指針執行D類型的任何操作都是安全的;但是,如果pb指向的是一個 B類型的對象,那么pd1將是一個指向該對象的指針,對它進行D類型的操作將是不安全的(如訪問m_szName),而pd2將是一個空指針。另外要注意:B要有虛函數,否則會編譯出錯;static_cast則沒有這個限制。這是由于運行時類型檢查需要運行時類型信息,而這個信息存儲在類的虛函數表(關于虛函數表的概念,詳細可見<Inside c++ object model>)中,只有定義了虛函數的類才有虛函數表,沒有定義虛函數的類是沒有虛函數表的。
另外,dynamic_cast還支持交叉轉換(cross cast)。如下代碼所示。
class A
{
public:
int m_iNum;
virtual void f(){}
};
?
class B:public A{
};
?
class D:public A
{
};
?
void foo()
{
B *pb = new B;
pb->m_iNum = 100;
D *pd1 = static_cast<D *>(pb); //copile error
D *pd2 = dynamic_cast<D *>(pb); //pd2 is NULL
delete pb;
}
在函數foo中,使用static_cast進行轉換是不被允許的,將在編譯時出錯;而使用 dynamic_cast的轉換則是允許的,結果是空指針。
reinpreter_cast
用法:reinpreter_cast<type-id> (expression_r_r)
type-id必須是一個指針、引用、算術類型、函數指針或者成員指針。它可以把一個指針轉換成一個整數,也可以把一個整數轉換成一個指針(先把一個指針轉換成一個整數,在把該整數轉換成原類型的指針,還可以得到原先的指針值)。
該運算符的用法比較多。
const_cast
用法:const_cast<type_id> (expression_r_r)
該運算符用來修改類型的const或volatile屬性。除了const 或volatile修飾之外, type_id和expression_r_r的類型是一樣的。
常量指針被轉化成非常量指針,并且仍然指向原來的對象;常量引用被轉換成非常量引用,并且仍然指向原來的對象;常量對象被轉換成非常量對象。
Voiatile和const類試。舉如下一例:
class B
{
public:
int m_iNum;
}
void foo()
{
const B b1;
b1.m_iNum = 100; //comile error
B b2 = const_cast<B>(b1);
b2. m_iNum = 200; //fine
}
上面的代碼編譯時會報錯,因為b1是一個常量對象,不能對它進行改變;使用const_cast把它轉換成一個常量對象,就可以對它的數據成員任意改變。注意:b1和b2是兩個不同的對象。
最容易理解的解釋:
???dynamic_cast: ??通常在基類和派生類之間轉換時使用;
???const_cast: ??主要針對const和volatile的轉換.???
???static_cast: ??一般的轉換,如果你不知道該用哪個,就用這個。???
???reinterpret_cast: ??用于進行沒有任何關聯之間的轉換,比如一個字符指針轉換為一個整形數。
dynamic_cast的注意事項 dynamic_cast轉換符只能用于指針或者引用。dynamic_cast轉換符只能用于含有虛函數的類。dynamic_cast轉換操作符在執行類型轉換時首先將檢查能否成功轉換,如果能成功轉換則轉換之,如果轉換失敗,如果是指針則反回一個0值,如果是轉換的是引用,則拋出一個bad_cast異常,所以在使用dynamic_cast轉換之間應使用if語句對其轉換成功與否進行測試,比如pd = dynamic_cast(pb); if(pd){…}else{…},或者這樣測試if(dynamic_cast(pb)){…}else{…}。
因此,dynamic_cast操作符一次執行兩個操作。首先驗證被請求的轉換是否有效,只有轉換有效,操作符才實際進行轉換。基類的指針可以賦值為指向派生類的對象,同樣,基類的引用也可以用派生類對象初始化,因此,dynamic_cast操作符執行的驗證必須在運行時進行。
2、const_cast操作符 其表達式為?const_cast<類型>(表達式),
其中類型指要把表達式轉換為的目標類型。該操作符用于改變const和volatile,const_cast最常用的用途就是刪除const屬性,如果某個變量在大多數時候是常量,而在某個時候又是需要修改的,這時就可以使用const_cast操作符了。 const_cast操作符不能改變類型的其他方面,他只能改變const或volatile,即const_cast不能把int改變為double,但可以把const int改變為int。const_cast只能用于指針或引用。
const_cast的用法舉例 比如:int a=3; const int *b=&a; int* c=const_cast(b); *c=4; cout<<a<<*c;這時輸出兩個4,如果不使用const_cast轉換符則常量指針*c的值是不能改變的,在這里使用const_cast操作符,通過指針b就能改變常量指針和變量a的值。
3、static_cast操作符 該操作符用于非多態類型的轉換,任何標準轉換都可以使用他,即static_cast可以把int轉換為double,但不能把兩個不相關的類對象進行轉換,比如類A不能轉換為一個不相關的類B類型。static_cast本質上是傳統c語言強制轉換的替代品。
static_cast(靜態轉換)執行非多態的轉換,用于代替C中通常的轉換操作。因此,被做為隱式類型轉換使用。顯式告訴編譯器,不關心轉換后精度損失。比如:int i;float f = 166.7f;i = static_cast<int>(f);此時結果,i的值為166。
4、reinterpret_cast操作符 該操作符用于將一種類型轉換為另一種不同的類型,比如可以把一個整型轉換為一個指針,或把一個指針轉換為一個整型,因此使用該操作符的危險性較高,一般不應使用該操作符。
reinterpret_cast(重述轉換)主要是將數據從一種類型的轉換為另一種類型。所謂“通常為操作數的位模式提供較低層的重新解釋”也就是說將數據以二進制存在形式的重新解釋。比如: int i;char *p = "This is a example.";i = reinterpret_cast<int>(p);此時結果,i與p的值是完全相同的。reinterpret_cast的作用是說將指針p的值以二進制(位模式)的方式被解釋為整型,并賦給i,一個明顯的現象是在轉換前后沒有數位損失,即一定不改變元數據。?
關于reinterpret_cast,使用這個操作符的類型轉換,其的轉換結果幾乎都是執行期定義(implementation-defined)。因此,使用reinterpret_casts的代碼很難移植。?
reinterpret_casts的最普通的用途就是在函數指針類型之間進行轉換。例如,假設你有一個函數指針數組:
typedef void (*FuncPtr)(); // FuncPtr是一個指向函數的指針,該函數沒有參數返回值類型為void
FuncPtr funcPtrArray[10]; // funcPtrArray是一個能容納10個FuncPtrs指針的數組?
讓我們假設你希望(因為某些莫名其妙的原因)把一個指向下面函數的指針存入funcPtrArray數組:
int doSomething();
你不能不經過類型轉換而直接去做,因為doSomething函數對于funcPtrArray數組來說有一個錯誤的類型。在FuncPtrArray數組里的函數返回值是void類型,而doSomething函數返回值是int類型。
funcPtrArray[0] ?= ?&doSomething;?// 錯誤!類型不匹配reinterpret_cast可以讓你迫使編譯器以你的方法去看待它們
funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething);?// this compiles?
?
轉換函數指針的代碼是不可移植的(C++不保證所有的函數指針都被用一樣的方法表示),在一些情況下這樣的轉換會產生不正確的結果。
總結
以上是生活随笔為你收集整理的C++四种强制类型转换 dynamic_cast,const_cast,static_cast,reinterpret_cast的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++实现反射
- 下一篇: C++原子操作 atomic的使用及效率