C++學習之路(六):關於C++提供的強制類型轉換
C語言中提供了舊式的強制類型轉換方法。比如:
int a =1;
char *p = (char *)&a;
上述將a的地址單元強制轉換為char類型的指針。這裏暫且不說上述轉換結果是否合理,但上述這樣的強制類型轉換,如果轉換過程出現問題,對於問題的追蹤與排查也比較困難。
對於C++而言,提供了較為安全的強制類型轉換方法,下面進行簡單介紹。
一、static_cast
對於任何具有明確定義的類型轉換,只要不包含底層const,都可以用static_cast。
主要可以有以下幾種轉換:
(1)用於基本數據類型之間的轉換,如把int轉換為char,把int轉換為enum,但這裏的轉換的安全性需要由開發者自己保證;
(2)把空指針轉換成目標類型的指針,這裏有點類似舊式的強制類型轉換的void*指針轉換,但同樣,對指針類型的解析,需要由開發者自己保證
(3)把任何類型的表達式類型轉換為void類型;
(4)用於類層次結構中父類和子類之間指針和引用的轉換。
上面的幾點後續遇到了樣例再進行補充,這裏給一個轉換void*指針的樣例說明。
代碼1:
int a = 1; char *q = static_cast<char*>(&a); cout<<*q<<endl;
上述代碼不能被編譯通過,因為static_cast對於指針的轉換,只能接受void*類型,上述&a依然是int型指針,不能通過編譯。
代碼2:
int a = 1; char *q = static_cast<char*>((void *)&a); cout<<*q<<endl;
通過將&a轉型為void*指針,完成對類型的強制轉換,上述代碼結果正常輸出。
二、const_cast
在由const關鍵字定義的變量,是不能在後續被修改的。比如:
const int a = 1;
a = 2;
上述編譯不通過,因為a不能被進行修改。
這裏我們依然先看一個樣例:
int func(int &a) { return 0; } int main(void) { const int a = 1; func(a); return 0; }
上述代碼中,a是一個const變量,但在func函數中的形參需要一個int型變量。很顯然,編譯直接報錯,因為實參與形參具有不同的類型。如何解決這個問題?這就需要引入const_cast進行類型轉換
const_cast只能改變運算對象的底層const。即對於一個const對象,const_cast可以將其const限定移除。上述代碼修改為:
int func(int *a) { return 0; } int main(void) { const int a = 1; int *p = const_cast<int*>(&a); func(p); }
這裏將const的變量a的指針,強制類型轉換為非const的指針,在func中傳入指針變量,程序即可以成功編譯。
這裏就有一個疑問:如果可以const_cast將const變量轉換為非const變量,是否意味著,可以對const變量進行修改?如果可以,那是不是違背了const關鍵字的初衷? 這裏再看一個樣例代碼:
int main(void) { const int a = 5; const int *p = &a; int *q = const_cast<int*>(p); cout<<&a<<endl; cout<<p<<endl; cout<<q<<endl; cout<<*q<<endl; *q = 6; cout<<*p<<endl; cout<<a<<endl; return 0; }
a是一個const變量,p是一個const指針指向a,q通過const_cast強制類型轉換p得到一個非const指針。
直接貼出程序結果,再進行分析:
結果可以看到,&a,p,q的值都是相同的,證明p和q指針都正確指向了a的地址單元。接下來輸出*q,為a的原值5,再對*q進行了修改,輸出*p,結果為成功修改後的6。但最後輸出a變量,發現a變量依然為原值5。
結論很明顯了:對於const變量,仍然不能夠修改它本身的值,這是限定符自身的約束。
三、reinterpret_cast
關於reinterpret_cast,感覺更比較貼合舊式的強制類型轉換。舉個例子:
int a = 1; char *q = reinterpret_cast<char*>(&a); cout<<*q<<endl;
上述對於static_cast的使用,需要對&a轉換為void*才能夠進行,但使用reinterpret_cast則可以直接進行轉換。reinterpret_cast本質上依賴於機器。
四、dynamic_cast
關於dynamic_cast,用法比較豐富,會再之後進行討論。
結論:對於一條強制類型轉換的語句,都應該反復斟酌是否能用其他方式來實現相同的目標,就算實在無法避免,也應用盡量限制類型轉換值的作用域,並記錄對相關類型的所有假定,這樣可以減少錯誤發生的機會。
C++學習之路(六):關於C++提供的強制類型轉換