類型轉換可以讓我們將一種類型的變量當做另外一種類型來使用,常見的類型轉換方式包括
C風格的類型轉換
轉換格式爲:(類型)變量
int a = 10; double b = a; float c = b;
Base* base = (Base*)new Derived();
C++自帶的類型轉換
- static_cast
- dynamic_cast
- const_cast
- reinterpret_cast
爲什麼有了C風格的類型轉換方式後C++還添加這四種類型轉換方式呢?
因爲C風格的類型轉換可以在任意類型之間轉換,比如你可以把一個指向const對象的指針轉換成指向非const對象的指針,把一個指向基類對象的指針轉換成指向一個派生類對象的指針,這兩種轉換之間的差別是巨大的,但是傳統的c語言風格的類型轉換沒有區分這些。還有一個缺點就是,c風格的轉換不容易查找,他由一個括號加上一個標識符組成,而這樣的東西在c++程序裏一大堆。
static_cast
類似與C風格的無條件靜態類型轉換
1、基類和子類之間的轉換,其中:子類->基類是安全的,但是基類->子類是不安全的,建議使用dynamic_cast進行運行時判斷進行基類轉子類。
2、基本數據類型之間的轉換,int, char, float,注意不可以進行無關類型指針的轉換。
3、轉換空指針爲任何類型的空指針
Base* base1 = static_cast<Base*>(new Derived()); Derived* base2 = static_cast<Derived*>(new Base()); //基類->子類,有風險,不推薦使用 double num = static_cast<double>('a'); //char->double // double* ptr = static_cast<double*>(new int(10)); 錯誤,無關類型的指針轉換,轉換無效 double* ptr = static_cast<double*>(nullptr); //空指針->任意類型的空指針
dynamic_cast
動態轉換主要是用於類的層次間、基類子類間轉換,具有檢驗功能,在無法進行轉換時返回nullptr。如果轉換的是引用,失敗時會拋出std::base_cast異常。可以通過返回值進行判斷是否成功轉換。
Base* base = dynamic_cast<Base*>(new Derived()); //成功 if (base == nullptr) { std::cout << "derived -> base 失敗" << std::endl; } Derived* derived = dynamic_cast<Derived*>(new Base()); //失敗 if (derived == nullptr) { std::cout << "base -> derived 失敗" << std::endl; }
返回失敗
const_cast
用於移除、添加變量的const屬性,注意C++中其他的三類轉換都沒有移除const屬性的能力,對於const_cast主要用來對頂層、底層的const進行轉換。爲什麼不可以對變量的const進行修改呢?因爲沒有意義。
int i = 10; const int* p = &i; const int* ci = const_cast<const int*>(p); //*ci = 20; 提示錯誤,表達式必須是可修改的左值 int* c = const_cast<int*>(p); *c = 20;
reinterpret_cast
re重新的意思,interpret解讀、翻譯的意思,顧名思義將數據重新按照另外一種類型進行解讀,一般很少用到,不清楚自己在操作什麼數據時,請謹慎使用。比如將四個字符當做當做一個浮點數進行處理。
char ch[4] = { 'a', 'b', 'c', 'd' }; float* f = reinterpret_cast<float*>(ch); //四個字符共四個字節正好當做一個浮點數來處理(不嚴謹,具體根據各個平臺浮點數字節大小可能不一樣) std::cout << *f << std::endl;
輸出
本質上C++中的四種類型轉換都是語法糖,所有能做的C風格轉換也可以做到。但是使用C++中的類型轉換,可以讓我們更好的追蹤到我們的項目裏面的哪裏有用到類型轉換,這是C風格轉換所不具有的優勢的。
更多參考: