顯式類型轉換
reinterpret_cast<new_type>(EXPression)顯式轉換
const_cast<new_type>(EXPression) 顯式轉換
static_cast<new_type>(EXPression) 顯式轉換
dynamic_cast<new_type>(EXPression) 顯式轉換
功能: 將EXPression表達式的值轉換爲 new_type類型的值。
1 前三種類型的轉換是在編譯時期 實現轉換的,
最後一個是在運行時期 進行類型轉換的,而且返回轉換成功與否標誌,這是傳統的類型轉換所不具有的功能
double d=3.2;
int i= d; //隱式轉換double變量d 爲int 變量, i=3
假若使用C++顯式類型轉換 static_cast(exp)函數作以上一樣的事,就可讓他人知道這樣的double 到 int 類型的轉換,是有意這麼作的,
並不是疏忽大意所致。
double d=3.2;
int i = static_cast<int>(d);//顯式轉換
A reinterpret_cast 類型轉換函數將一個類型的指針,轉換爲另外一個類型的指針。這種轉換不用改變指針變量值數據存放格式(不改變指針變量值),只需在編譯時從新解釋指針的類型就能夠作到。reinterpret_cast 能夠將指針轉換爲一個整形數(隱式轉換),但不能用於非指針類型的轉換,即便這樣作也不會經過編譯
1> 用顯式的reinterpret_cast 將基本類型或一個類的指針,轉換爲另外一個類型或類的指針
//基本類型指針的類型轉換
double d=9.3;
double* pd = &d;
int *pi = reinterpret_cast<int* >(pd); //至關於隱式轉換 int* pi = (int* )pd;
2>
//不相關的類的指針的類型轉換
class A{}; class B{};
A* pa = new A;
B* pb = reinterpret_cast<B* >(pa); // 至關於隱式轉換 B* pb = (B*)pa;
3> 指針轉換爲整數
long j = reinterpret_cast<long>(pi); //至關於隱式轉換 long j = (long)pi;
4> 嘗試將int 類型的變量轉換爲double 類型,因爲並不是指針類型轉換,所以轉換不成功.
//企圖轉換非指針變量
int i=8;
double dl = reinterpret_cast<double>(i); //不能編譯經過
//企圖轉換 const 指針爲 void * 指針
const int* pci - 0;
void* pv = reinterpret_cast<void* >(pci); //不能編譯經過
B const_cast 類型轉換函數用於去除指針變量的常量屬性,將它轉換爲一個對應指針類型的普通變量。反過來,也能夠將一個很是量的指針變量轉換爲一個常指針變量。這種轉換是在編譯期間作出的類型更改。
1> 將int 類型的常指針便利pci 轉換爲int 指針變量,將類A的常指針便利pca 轉換爲類A的普通指針變量,將類A的常指針變量pca轉換爲類A的普通指針變量
const int* pci = 0;
int *pj = const_cast<int* >(pci); //至關於隱式轉換 int * pj = (int* )pci;
const A* pca = new A;
A *pa = const_cast<A*>(pca); //至關於隱式轉換 A* pa = (A*)pca;
2> 基於安全考慮,const_cast 沒法將非指針的常變量轉換爲普通變量
const int i = 0;
const_cast<int>(i); //去除變量i的常屬性,不能編譯經過
3>將普通指針變量pi 轉換爲常指針變量,但不能將非指針的普通變量轉換爲常變量。而隱式轉換則容許
int * pi = 0; //至關於隱式轉換 const int* pcj = (int*)pi;
const int* pcj = const_cast<const int* >(pi);
int i =0;
const int cj = const_cast<const int>(i); //非指針轉換,不能編譯經過
const int ck = (const int)i; // 隱式轉換, 可經過編譯
該運算符用來修改類型的const或volatile屬性。除了const 或volatile修飾以外, type_id和expression的類型是同樣的。
常量指針被轉化成很是量指針,而且仍然指向原來的對象;
常量引用被轉換成很是量引用,而且仍然指向原來的對象;常量對象被轉換成很是量對象。
volatile和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是兩個不一樣的對象。
C static_cast 主要用於基本類型之間 和具備繼承關係的類型之間的轉換,這種轉換通常會更改變量的內部表示方式,所以static_cast應用於指針類型轉換,沒有太大意義,即便容許指針類型轉換,也不及reinterpret_cast解釋效率高
static_cast類型轉換用於相關類型之間的轉換,諸如:在同一個類的繼承層次關係中,向上或向下轉換;枚舉類型與整數類型之間的轉換;浮點類型與指數類型之間的轉換。在這4中類型轉換中,static_cast是最接近C-style的了。html
該運算符把expression轉換爲type-id類型,但沒有運行時類型檢查來保證轉換的安全性。它主要有以下幾種用法:
(1)用於類層次結構中基類和派生類之間指針或引用的轉換
進行上行轉換(把派生類的指針或引用轉換成基類表示)是安全的
進行下行轉換(把基類的指針或引用轉換爲派生類表示),因爲沒有動態類型檢查,因此是不安全的
(2)用於基本數據類型之間的轉換,如把int轉換成char。這種轉換的安全也要開發人員來保證
(3)把空指針轉換成目標類型的空指針
(4)把任何類型的表達式轉換爲void類型
注意:static_cast不能轉換掉expression的const、volitale或者__unaligned屬性。c++
1> // 基本類型轉換
int i=0;
double d = static_cast<double>(i); //至關於隱式轉換 double d =(double)i;
int j = static_cast<int>(d); //至關於隱式轉換 int j = (int)d;
2> //轉換繼承類的對象爲基類對象
class Base{};
class Derived : public Base{};
Derived d;
Base b = static_cast<Base >(d); //至關於隱式轉換 Base b = (Base)d;
3> 以下將繼承類與基類的指針進行相互轉換,都能編譯經過,但基類指針轉換爲繼承類指針,具備必定的危害性.
// 繼承類指針 轉換爲基類指針
Derived* pd = new Derived;
Base* pb = static_cast<Base* >(pd); //至關於隱式轉換 Base* pb = (Derived*)pd;
// 基類指針轉換爲繼承類指針
Base* pb = new Base;
Derived* pd = static_cast<Derived* >(pb); //至關於隱式轉換 Derived* pd = (Dervived*)pb;
4> 如下代碼嘗試用static_cast 轉換基本數據類型的指針,將繼承類對象轉換爲基類對象或 轉換無繼承關係的類的指針,都不能編譯經過.
class A{};
class B{};
int *pi = 0;
double *pd = static_cast<double* >(pi); //企圖int* 轉換爲 double* , 不能編譯經過
//
Base b;
Derived d = static_cast<Derived>(b); //企圖繼承類對象轉換爲基類對象,不能編譯經過
//
A a;
B b = static_cast<B>(a); //企圖轉換無繼承關係的類, 不能編譯經過
A * pa = NULL;
B* pb = static_cast<B*>(pa); // 企圖轉換無繼承關係的類的指針,不能編譯經過
D dynamic_cast 與 靜態static_cast 相對, 是動態的轉換。這種轉換是在運行時進行轉換分析的,並不是在編譯時期進行。
dynamic_cast 只能在繼承類對象的指針之間 或 引用之間 進行類型轉換。進行轉換時,會根據當前運行對象的運行時類型信息(RTTI),判斷類型對象之間的轉換是否合法。dynamic_cast的指針轉換失敗,可經過是否爲NULL指針檢測; 引用轉換失敗,則拋出一個bad_cast異常。express
用法:dynamic_cast<type_id> (expression)
該運算符把expression轉換成type_id類型的對象。type_id必須是類的指針、引用或者void*;
若是type_id是類指針類型,那麼expression也必須是一個指針,若是type_id是一個引用,那麼expression也必須是一個引用。
dynamic_cast主要用於類層次間的上行轉換和下行轉換,還能夠用於類之間的交叉轉換。
在類層次間進行上行轉換時,dynamic_cast和static_cast的效果是同樣的;
在進行下行轉換時,dynamic_cast具備類型檢查的功能,比static_cast更安全。安全
1> dynamic_cast 將繼承類指針或引用轉換爲 基類指針或引用, 並對沒有繼承關係, 但被轉換的類具備虛函數的對象指針進行轉換,都可編譯經過。
class Base{};
class Derived: public Base{};
//繼承類指針轉換爲基類指針
Derived* pd = new Derived();
Base* pb = dynamic_cast<Base* >(pd);
if(!pb)
printf("dynamic_cast 類型轉換失敗\n");
else
printf("dynamic_cast 類型轉換成功\n");
//有繼承關係的引用之間轉換
Derived d;
Base& b = dynamic_cast<Base& >(d);
//沒有繼承關係,但被轉換的類有虛函數
class A {virtual ~A(){}}; // 有虛函數
class B{};
A* pa = new A;
B* pb = dynamic_cast<B* >(pa); //有虛函數的對象指針,能夠轉換
if(!pb)
printf("dynamic_cast 類型轉換失敗\n");
else
printf("dynamic_cast 類型轉換成功\n");
2> 以下代碼嘗試將非指針的繼承對象轉換爲 基類對象, 對無繼承關係(且沒有虛函數)的對象指針進行轉換, 基本類型指針轉換 以及基類指針轉換爲繼承類指針,均不能編譯經過
class A{}; //沒有虛函數
class B{virtual ~B(){}};
//繼承類轉換爲基類對象, 不能編譯經過
Derived d;
Base b = dynamic_cast<Base>(d);
//無繼承關係,且A 無虛函數, A類對象指針轉換, 不能編譯經過
A* pa = new A;
B* pb = dynamic_cast<B* >(pa);
// 基本類型之間轉換(無繼承關係), 不能經過
int* i=0;
int j = dynamic_cast<int* >(i);
//基類指針轉換爲繼承類指針, 不能編譯經過
Base* pb = new Base;
Derived *pd = dynamic_cast<Derived* >(pb);
3> dynamic_cast 不僅是應用於類型轉換,一般利用它作運行時對象類型檢查的特性,在程序中檢測當前內存對象的類型信息。ide
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還支持交叉轉換,以下所示。
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); //compile error
D *pd2 = dynamic_cast<D *>(pb); //pd2 is NULL
delete pb;
}
在函數foo中,使用static_cast進行轉換是不被容許的,將在編譯時出錯,而使用dynamic_cast轉換則是容許的,結果是空指針。
zongjiegoogle
在寫代碼中常常會有不少的隱式類型轉換或顯式類型轉換。spa
對於隱式的類型轉換主要是放生在賦值的時候,講變量賦值給不一樣類型的變量的時候就會發生類型轉換,若是是寬化轉換(即從佔字節少的類型向佔字節多的 類型轉換),這個時候是不會出現丟失數據的。若是是窄化轉換(從佔字節多的類型向佔字節少的類型轉換),這個時候就頗有可能會出現丟失數據,或者數據錯誤 (如從有符號向無符號轉換,就可能會出現各類沒法想象的問題)。。。因此這種狀況應該儘可能避免。.net
對於C風格顯式轉換,就是強制轉換,可能會形成數據解釋錯誤,也是很不安全的。指針
在C++中有四種類型轉換:
靜態轉換相似於C風格顯式轉換,可是會判斷轉換類型之間的關係,若是轉換類型之間沒有任何關係,則不可轉換,編譯器會報錯。(不相關類型之間不能夠發生轉換).
動態轉換有兩個約束條件:其一是要求new_type爲指針或引用,其二是下行轉換時要求基類是多態的(基類中包含至少一個虛函數)。
動態轉換支持上行轉換和下行轉換,可是對於不安全的下行轉換,會返回NULL,提升安全性(上行轉換:子類轉化爲父類,下行轉換:父類轉化爲子類)。
重解釋轉換則是任何兩個類型之間均可以轉換,是最不安全的一種類型轉換,儘可能不要用。
將常量轉換爲很是量,這個轉換並不轉換原常量自己,只是它返回的結果爲很是量了
http://blog.csdn.net/coding_hello/article/details/2211466
http://www.xuebuyuan.com/1554696.html
http://www.2cto.com/kf/201411/353737.html
http://blog.csdn.net/thesys/article/details/5651713https://www.google.com.hk/search?q=ttp://blog.csdn.net/pongba/archive/2004/09/01/90642.aspx&ie=utf-8&oe=utf-8&gws_rd=cr&ei=tWTLVM7UJMTU8gXN5IGwBAhttp://blog.csdn.net/pongba/article/details/90642http://blog.csdn.net/pongba/article/details/2544894http://blog.csdn.net/pongba/article/list/2http://blog.csdn.net/pongba/article/list/2http://blog.csdn.net/pongba/article/list/2