1. 程式人生 > >淺談C++中的四種類型轉換

淺談C++中的四種類型轉換

轉換的含義是通過改變一個變數的型別為別的型別從而改變該變數的表示方式。為了型別轉換一個簡單物件為另一個物件你會使用傳統的型別轉換操作符。

型轉換有c風格的,當然還有c++風格的。c風格的轉換的格式很簡單(TYPE)EXPRESSION;例如將為了轉換一個型別為doubole的浮點數的指標到整型:

程式碼:
int i;

double d;

i = (int) d;

或者:

i = int (d);

但是c風格的型別轉換有不少的缺點,有的時候用c風格的轉換是不合適的,因為它可以在任意型別之間轉換,比如你可以把一個指向const物件的指標轉換 成指向非const物件的指標,把一個指向基類物件的指標轉換成指向一個派生類物件的指標,這兩種轉換之間的差別是巨大的,但是傳統的c語言風格的型別轉 換沒有區分這些。還有一個缺點就是,C風格的轉換不容易查詢,他由一個括號加上一個識別符號組成,而這樣的東西在c++程式裡一大堆。

C++標準定義了四個新的轉換符:'reinterpret_cast', 'static_cast', 'dynamic_cast' 和 'const_cast',目的在於控制類(class)之間的型別轉換。
程式碼:
 reinterpret_cast<new_type>(expression)  //解釋型別轉換

dynamic_cast<new_type>(expression)//動態型別轉換

static_cast<new_type>(expression)  //靜態型別轉換

const_cast<new_type>(expression)//常量型別轉換

1、static_cast 

用法用法:static_cast < type-id > ( expression ) 

最常用的型別轉換符,在正常狀況下的型別轉換,如把int轉換為float,如:int i;float f; f=(float)i;或者f=static_cast<float>(i); 在一類東西都可以轉, 但是不是一類的就不能轉. 即, 語義上說不通的, 兩個完全不同的資料型別 static_cast 是拒絕工作的. 比如你想把一個指標轉成浮點數, 或者想把 class A * 轉成 class B * , 但是 class A 和 class B 又沒有任何關係. 等等...static_cast 在通過編譯後, 空間和時間效率實際等價於 C 方式強制轉換. 都是編譯時決定的. 

下面是其詳細使用說明:

(1)用於類層次結構中基類和子類之間指標或引用的轉換。進行上行轉換(把子類的指標或引用轉換成基類表示)是安全的;進行下行轉換(把基類指標或引用轉換成子類表示)時,由於沒有動態型別檢查,所以是不安全的。

(2)用於基本資料型別之間的轉換,如把int轉換成char,把int轉換成enum。這種轉換的安全性也要開發人員來保證。

(3)把空指標轉換成目標型別的空指標。

(4)把任何型別的表示式轉換成void型別。

注意:static_cast不能轉換掉expression的const、volitale、或者__unaligned屬性。

2、const_cast

用法用法:const_cast<type_id> (expression)

const_cast 一般用於強制消除物件的常量性把const型別的指標變為非const型別的指標,它是唯一能做到這一點的 C++ 風格的強制轉型

如:,

const int *fun(int x,int y){}  

int *ptr=const_cast<int *>(fun(2.3))

再舉例如下:

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是一個常量物件,不能對它進行改變;

3、dynamic_cast

用法:dynamic_cast < type-id > ( expression )
dynamic_cast'只用於物件的指標和引用。當用於多型型別時,它允許任意的隱式型別轉換以及相反過程。不過,與static_cast不同,在後一種情況裡(注:即隱式轉換的相反過程),dynamic_cast會檢查操作是否有效。也就是說,它會檢查轉換是否會返回一個被請求的有效的完整物件。檢測在執行時進行。如果被轉換的指標不是一個被請求的有效完整的物件指標,返回值為NULL.。 如果type-id是類指標型別,那麼expression也必須是一個指標,如果type-id是一個引用,那麼expression也必須是一個引用。   dynamic_cast主要用於類層次間的上行轉換和下行轉換,還可以用於類之間的交叉轉換。在類層次間進行上行轉換時,dynamic_cast和static_cast的效果是一樣的;在進行下行轉換時,dynamic_cast具有型別檢查的功能,比static_cast更安全。下面為dynamic_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則沒有這個限制。這是由於執行時型別檢查需要執行時型別資訊,而這個資訊儲存在類的虛擬函式表中,只有定義了虛擬函式的類才有虛擬函式表,沒有定義虛擬函式的類是沒有虛擬函式表的。另外,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); //compile error   D *pd2 = dynamic_cast<D *>(pb); //pd2 is NULL   delete pb; }   在函式foo中,使用static_cast進行轉換是不被允許的,將在編譯時出錯;而使用 dynamic_cast的轉換則是允許的,結果是空指標。

4、reinterpret_cast

用法: reinterpret_cast < type-id > ( expression )  reinterpret_cast是C++裡的強制型別轉換符。

'reinterpret_cast'轉換一個指標為其它型別的指標。這個操作符能夠在非相關的型別之間轉換。操作結果只是簡單的從一個指標到別的指標的值的二進位制拷貝。在型別之間指向的內容不做任何型別的檢查和轉換。

例如: int *n= new int ;   double *d=reinterpret_cast<double*> (n); 在進行計算以後, d 包含無用值. 這是因為 reinterpret_cast 僅僅是複製 n 的位元位到 d, 沒有進行必要的分析。因此, 需要謹慎使用 reinterpret_cast.並且:reinterpret_cast 只能在指標之間轉換。reinterpret_cast是為了對映到一個完全不同型別的意思,這個關鍵詞在我們需要把型別映射回原有型別時用到它。我們對映到的型別僅僅是為了故弄玄虛和其他目的,這是所有對映中最危險的。 static_cast 和 reinterpret_cast 操作符修改了運算元型別。它們不是互逆的; static_cast 在編譯時使用型別資訊執行轉換,在轉換執行必要的檢測(諸如指標越界計算, 型別檢查). 其運算元相對是安全的。另一方面;reinterpret_cast 僅僅是重新解釋了給出的物件的位元模型而沒有進行二進位制轉換, 例子如下: int n=9;  double d=static_cast < double > (n);   上面的例子中, 我們將一個變數從 int 轉換到 double。 這些型別的二進位制表示式是不同的。 要將整數 9 轉換到 雙精度整數 9,static_cast 需要正確地為雙精度整數 d 補足位元位。其結果為 9.0。而reinterpret_cast 的行為卻不同:   int n=9; double d=reinterpret_cast<double & > (n); 這次, 結果有所不同. 在進行計算以後, d 包含無用值. 這是因為 reinterpret_cast 僅僅是複製 n 的位元位到 d, 沒有進行必要的分析.