程式扎記: [C++ 文章收集] 標準C++的類型轉換 : static_cast, dynamic_cast, reinterpret_cast 與 const_cast

標籤

2010年8月5日 星期四

[C++ 文章收集] 標準C++的類型轉換 : static_cast, dynamic_cast, reinterpret_cast 與 const_cast

轉載自 這裡 
前言 : 
關於強制類型轉換的問題,很多書都討論過,寫的最詳細的是C++之父的《C++的設計和演化》. 最好的解決方法就是不要使用C風格的強制類型轉換,而是使用標準C++的類型轉換符:static_cast, dynamic_cast. 標準C++中有四個類型轉換符 : static_cast、dynamic_cast、reinterpret_cast、和const_cast. 下面對它們一一進行介紹. 

static_cast : 
用法:static_cast < type-id > ( expression ) 
該運算符把expression轉換為type-id類型,但沒有運行時類型檢查來保證轉換的安全性。 它主要有如下幾種用法 : 

* 用於類層次結構中基類和子類之間指針或引用的轉換。 進行上行轉換(把子類的指針或引用轉換成基類表示)是安全的;進行下行轉換(把基類指針或引用轉換成子類表示)時,由於沒有動態類型檢查,所以是不安全的。
* 用於基本數據類型之間的轉換,如把int轉換成char,把int轉換成enum。 這種轉換的安全性也要開發人員來保證。
* 把空指針轉換成目標類型的空指針。
* 把任何類型的表達式轉換成void類型。

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

dynamic_cast : 
用法: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. class B{  
  2. public:  
  3.     int m_iNum;  
  4.     virtual void foo();  
  5. };  
  6.   
  7. class D:public B{  
  8. public:  
  9.     char *m_szName[100];  
  10. };  
  11. void func(B *pb) {  
  12.     D *pd1 = static_cast(pb);  
  13.     D *pd2 = dynamic_cast(pb);  
  14. }  

在上面的代碼段中,如果pb指向一個D類型的對象,pd1和pd2是一樣的,並且對這兩個指針執行D類型的任何操作都是安全的;但是,如果pb指向的是一個B類型的對象,那麼pd1將是一個指向該對象的指針,對它進行D類型的操作將是不安全的(如訪問m_szName),而pd2將是一個空指針。 另外要注意:B要有虛函數,否則會編譯出錯;static_cast則沒有這個限制。 這是由於運行時類型檢查需要運行時類型信息,而這個信息存儲在類的虛函數表(關於虛函數表的概念,詳細可見)中,只有定義了虛函數的類才有虛函數表,沒有定義虛函數的類是沒有虛函數表的. 另外,dynamic_cast 還支持交叉轉換 (cross cast). 請參考下面代碼 : 
- 範例代碼 :
  1. class A{  
  2. public:  
  3.     int m_iNum;  
  4.     virtual void f(){}  
  5. };  
  6.   
  7.   
  8. class B:public A{  
  9.   
  10. };  
  11.   
  12. class D:public A{  
  13.   
  14. };  
  15. #include   
  16. void foo() {  
  17.     B* pb = new B;  
  18.     pb->m_iNum = 100;  
  19.     //D *pd1 = static_cast(pb); //compile error  
  20.     D *pd2 = dynamic_cast(pb); //pd2 is NULL  
  21.     if(pd2==NULL){printf("pd2 is NULL!\n");}  
  22.     delete pb;  
  23. }  

在函數foo中,使用 static_cast 進行轉換是不被允許的,將在編譯時出錯;而使用 dynamic_cast 的轉換則是允許的,結果是空指針. 

reinpreter_cast : 
用法:reinpreter_cast (expression) 
type-id必須是一個指針、引用、算術類型、函數指針或者成員指針. 它可以把一個指針轉換成一個整數,也可以把一個整數轉換成一個指針(先把一個指針轉換成一個整數,在把該整數轉換成原類型的指針,還可以得到原先的指針值). 

const_cast : 
用法:const_cast (expression) 
該運算符用來修改類型的const或volatile屬性。 除了const 或volatile修飾之外, type_id和expression的類型是一樣的. 
常量指針被轉化成非常量指針,並且仍然指向原來的對象;常量引用被轉換成非常量引用,並且仍然指向原來的對象, 參考下面代碼 : 
- 範例代碼 :
  1. #include   
  2. #include   
  3. #include   
  4.   
  5. using namespace std;  
  6. void main() {  
  7.     const char str[] = "Test String";  
  8.     char* cs_Str = const_cast<char*>(str);  
  9.     cs_Str[0] = 'K';  
  10.     printf("str: %s\n", str);  
  11.     printf("cs_Str: %s\n", cs_Str);  
  12. }  

執行結果 : 
str: Kest String
cs_Str: Kest String

使用 const_cast 將 const char* 修改後即可對之進行修改.

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!