C++豐富的基本型別允許根據需求選擇不同的基本型別:11種整型和3種浮點型。在處理大量不同情況,尤其是對不同類型進行運算時,存在潛在的混亂。因此,C++支援自動執行很多型別轉換:
- 將一種算數型別的值賦給另一種算數型別的變數時,C++將對值進行轉換。
- 表達式中包含不同的型別時,C++將對值進行轉換。
- 將參數傳遞給函數時,C++將對值進行轉換。
1 初始化和賦值進行的轉換
賦值後值將被轉換爲接收變數的型別。
有些轉換是相對安全的:
- 將一個值賦給取值範圍更大的型別通常不會導致什麼問題,如short值賦給long變數,只是可能佔用更多位元組而已。
- 將零賦給bool變數時會轉換成false,將非零值賦給bool變數時會轉換成true。
還有些轉換則會帶來麻煩:
- 但將一個很大的long值賦給float變數時將降低精度,因爲float只有6位有效數位。
- 將大浮點型別轉換爲較小的浮點型別,如double值轉換爲float,會降低精度甚至超出目標型別的取值範圍,結果不確定。
- 將浮點型轉換爲整型,將會導致小數部分消失(截短),甚至超出目標取值範圍,結果不確定(不同系統不一樣)。
- 將較大的整型轉換爲較小的整型,可能會超出目標型別的取值範圍,通常只複製右邊的位元組。
傳統初始化行爲和賦值相同。
C++11使用大括號{}初始化(即列表初始化)時對型別轉換要求更嚴格。
- 列表初始化不允許縮窄,即變數的型別可能無法表示賦給它的值,如不允許將浮點型轉換爲整型。
- 在不同整型之間轉換或將整型轉換爲浮點型可能被允許,條件是編譯器知道目標變數能夠正確地儲存賦給它的值。
2 表達式中的轉換
當同一個表達式中包含兩種不同的算數型別時,有以下情況:
- 一些型別在出現時自動轉換:在計算表達式時,C++將bool、char、unsigned char、signed char和short值轉換爲int,即整型提升,再將計算結果轉換爲接收變數型別賦給該變數。(int型別爲計算最自然的型別,運算速度可能最快。)
- 還有一些其他整型提升:若short比int短,則unsigned short型別將被轉換爲int;若兩種型別長度相同,則unsigned short型別將被轉換爲unsigned int。由此確保在對unsigned short進行提升時不會損失數據。
- 同樣,wchar_t被提升成爲int、unsigned int、long和unsigned long中第一個寬度足夠儲存wchar_t取值範圍的型別。
- 還有些型別在與其他型別同時出現時將被轉換:不同類型進行運算時,較小型別會轉化爲較大型別。
C++11版本的編譯器校驗表順序:long double,double,float,整型提升。整型提升滿足:
- 有符號整型級別:long long、long、int、short和signed char。無符號整級別與有符號相同。型別char、unsigned char和signed char的級別相同。wchar_t、char16_t和char32_t的級別與其底層型別相同。
- 如果兩個運算元都是有符號的或無符號的,低級別的型別轉換爲高級別的。
- 如果一個有符號,一個無符號且級別高,則將有符號的運算元型別轉換爲無符號運算元所屬型別;如果有符號型別的能表示無符號型別的所有取值,則無符號的運算元型別轉換爲有符號運算元所屬型別;否則,將兩個運算元都轉換爲有符號型別的無符號版本。
3 傳遞參數時的型別轉換
傳遞參數時的型別轉換通常由C++函數原型控制。
- 可以取消原型對參數轉換的控制,但這樣作並不明智。
- C++對char和short型別(signed和unsigned)應用整型提升。
- 爲保證與傳統C的相容性,在將參數傳遞給取消原型對應參數傳遞控制的函數時, C++將float參數提升爲double。
4 強制型別轉換
C++允許通過強制型別轉換機制 機製顯示地進行型別轉換。
int haha = 1;
long haha1 = (long)haha; //來自C語言
long haha2 = long(haha); //純粹的C++
static_cast<long> haha; //haha程式設計long型別
強制型別轉換並不會改變haha變數本身,而是建立一個新的制定型別的值,可以在表達式中使用這個值。C++新格式使強制型別轉換就像是函數呼叫。
C++還引入4個強制型別轉換運算子。
- static_cast<>可用於將變數本身的值從一種型別轉換爲另一種型別。
- dynamic_cast<>
- const_cast<>
- reinterpret_cast<>
使用強制轉換的原因:
- 可能有一些值被預設存爲double型別,但要使用它們計算得到一個int型別的值。將兩個double值求和再前值轉換爲int型別,與將兩者先強制轉換成int型別再求和得到的結果很可能是不同的。
- 使用一種格式的數據能滿足不同的期望。
5 C++11的auto宣告
auto讓編譯器能夠根據初始值的型別推斷變數的型別。
- auto本是一個C語言關鍵字,但很少使用。
- 在初始化宣告中若使用auto而不指定變數型別,編譯器吧變數的型別設定成與初始值相同。(容易誤入歧途)
auto n = 100; //int
auto x = 1.5; //double
auto y = 1.3e12L; //long double
auto z = n; //int
處理複雜型別,如標準模組庫(STL)中的型別時,這種自動型別推斷便很有意義。
std::vector<double> scores;
std::vector<double>::iterator pv = scores.begin();
//第二句還可以表達爲
auto pv = scores.begin();