C++強制類型轉換
C++中的強制類型轉換雖然兼容C語言中的強制類型轉換。但是並不建議在C++中使用C語言風格的強制類型轉換。C++中的強制類型轉換共有4個關鍵字分別是:static_cast,const_cast,reinterpret_cast,dynamic_cast.
static_cast
用於將一種數據類型轉換成另一種數據類型,使用格式如下:
變量1 = static_cast<變量1數據類型>(另外一種數據類型變量或表達式);
例如:
int a = 1;
float b;
b = static_cast<float>(a); //類似於C語言中的b = (float)a;
const_cast
用於去除指針和引用的常量性,不能去除變量的常量性。使用格式如下:
指針或引用1 = const_cast<指針或引用1類型>(帶常量性的指針或引用2);
例如:
#include <iostream>
using namespace std;
int main()
{
int a = 10;
const int *p = &a; // 被const修飾,不能使用該指針修改其指向內容的值
int *q;
q = const_cast<int *>(p); // 去除p的常量性給q,如果不去除直接賦值會報錯
*q = 20;
cout<<"a的地址為:"<<&a<<" a的值為:"<<a<<endl;
cout<<"*q指向的地址為:"<<q<<" *q的值為:"<<*q<<endl;
}
執行結果如下:
a的地址為:0x61ff14a a的值為:20
*q指向的地址為:0x61ff14a *q的值為:20
為了加深理解,我們再看如下一段代碼:
#include <iostream>
using namespace std;
const int & Add5(int &a);
int main()
{
const int a = 10; //a的值不允許修改
int b = 20;
const int *p = &a; //被const修飾,不能使用該指針修改其指向內容的值
int *q;
q = const_cast<int *>(p); //去除p的常量性給q,如果不去除直接賦值會報錯
*q = 20;
cout<<"a的地址為:"<<&a<<" a的值為:"<<a<<endl;
cout<<"*q指向的地址為:"<<q<<" *q的值為:"<<*q<<endl;
cout<<"b的地址為:"<<&b<<" b的值為:"<<b<<endl;
int &m = const_cast<int &>(Add5(b)); //去掉函數的const屬性,不去掉就賦值給不帶const的引用會報錯
cout<<"調用加5函數之后"<<endl;
cout<<"引用m指向的地址為:"<<&m<<" 引用m指向的值為:"<<m<<endl;
}
//返回輸入值+5,返回的引用不可被修改
const int & Add5(int &a)
{
a+=5;
return a;
}
執行結果如下:
a的地址為0x61ff10 a的值為:10
*q指向的地址為:0x61ff10 *q的值為:20
b的地址為:0x61ff0c b的值為:20
調用加5函數之后
引用m指向的地址為:0x61ff0c 引用m指向的值為:25
上面這段程序有兩點說明:
- 對變量a加上了const屬性,因此a的值是不會被程序所改變的。即使我們將指向a的指針的const屬性去掉重新賦值,也不會改變。但是會出現變量a和指針q指向地址相同,但值不同的現象。
- 對變量b的操作我們可以看出,const_cast不僅僅能去掉指針的const,也能去掉引用的const。不僅僅能去掉變量表達式的const也能去掉函數的const。
最后,在強調一遍。const_cast不能去掉變量的const.這是編程安全的基礎。像下面這種操作是錯誤的。除了const之外,const_cast也能去掉volatile屬性,和去掉const一樣。
const int a = 10;
int b = const_cast<int>(a); //變量的const屬性去不掉,錯誤
reinterpret_cast
reinterpret_cast這種強制類型轉換是一種非常強的強制類型轉換,它可以將任意兩個無關的指針或引用進行轉換。上面的static_cast進行強制類型轉換時,會進行編譯時的類型安全檢查,即你可以將int轉成float,將子類引用(指針)轉成父類引用(指針),子轉父和父轉子都可以,但父轉子不安全。但是你不能使用static_cast將兩個無關的東西進行轉換,比如兩個無關的類,因為編譯器在編譯的時候會檢查這個轉換是否可行,很明顯不可行。
ClassB *p = &b;
ClassA *q = static_cast<ClassA &>(p); //如果ClassA和ClassB有關系,編譯能通過,否則不通過
但是如果使用的reinterpret_cast強制類型轉換,就不會進行靜態類型檢查直接放行通過。當然如果這兩個類如果沒有關系,那么在運行的過程就會“跑偏出錯”。為了防止在運行的過程中“跑偏”,我們除靜態類型轉換(static_cast)之外還需要一個動態的類型轉換(dynamic_cast).
dynamic_cast
前面我們介紹過了static_cast,從名稱上來看,兩個一動(dynamic)一靜(static)肯定有關系。我們知道static_cast會在編譯的過程中進行安全性檢查,而dynamic_cast會在運行的過程中進行安全性檢查。這兩個都帶安全性檢查可以防止錯誤的類型轉換導致程序跑偏。
dynamic_cast既然是動態安全性檢查,那么它肯定只能應用於指針或引用,不能用於內置的數據類型轉換(內置的數據類型轉換,在編譯階段由static_cast檢查即可)。dynamic_cast不但檢查兩個指針是否屬於同一個繼承樹(static_cast也檢查這個),還會檢測這種轉換是否可行。如果可行就會返回一個新指針,並計算出為處理多繼承的需要的必要的偏移量。如果不可行會返回NULL。因此即使我們使用reinterpret_cast強制類型轉換騙過編譯器編譯成功,如果我們在使用前再使用dynamic_cast轉換檢測一下的話,還是能發現這個錯誤的轉換的。
總結
- static_cast會進行靜態的安全性檢查,一般用於內置數據類型的轉換和通常的類之間的轉換。
- const_cast主要是用來去掉指針和引用的const和volatile類型。
- reinterpret_cast用於完全沒有關系指針或引用之間的轉換,比如字符指針轉整形指針。
- dynamic_cast通常用於基類和派生類之間的相互轉換。
