C++的類型轉換
——顯示轉換VS隱式轉換、轉換函數
合理的轉換可以使得程序更加簡潔,不合理的轉換往往導致程序錯誤和崩潰。C++類型的轉換可以分爲顯式轉換和隱式轉換兩種,顯示轉換是指通過類型轉換函數對類型進行轉換,隱式類型轉換是指由編譯器自動生成的轉換。隱式轉換的前提是存在合理的轉換對象。
l 隱式類型轉換髮生的場合——build-in類型
1. 兩種不同類型值進行比較或進行運算
這種隱式轉換是最常見的轉換,又叫做整型提升(integral promotion)。所有的比較操作符(==、>=、<=、!= )和算數運算符(+、-、*、/)都會出現這種情形。轉換規則是可以將char、signed char、unsigned char、short、and unsigned short提升到int。
E.g. bool flag; char cval;
short sval; unsigned short usval;
int ival; unsigned int uival;
long lval; unsigned long ulval;
float fval; double dval;
3.14159L + 'a'; // promote 'a' to int, then convert to long double
dval + ival; // ival converted to double
dval + fval; // fval converted to double
ival = dval; // dval converted (by truncation) to int
flag = dval; // if dval is 0, then flag is false, otherwise true
cval + fval; // cval promoted to int, that int converted to float
sval + cval; // sval and cval promoted to int
cval + lval; // cval converted to long
ival + ulval; // ival converted to unsigned long
usval + ival; // promotion depends on size of unsigned short and int
uival + lval; // conversion depends on size of unsigned int and long
ival >= dval // ival converted to double
2. 表達式轉換成bool類型
出現的情形有:
Ø 條件判斷語句中:if、while、for、do while和操作符(?:)的第一個判斷中。
Ø 邏輯操作符:邏輯非(!)、邏輯與(&&)和邏輯或(||)
只有當該類型的值爲0時,才能轉換成false,其他值都爲true。NULL指針類型可以轉換爲false,其他指針轉換後爲true。
E.g. int ival;
if (ival) // ival converted to bool, true if cp is not zero
while (cin) // cin converted to bool
while (cin >> s) //如果讀取失敗,則返回false,否則返回true
3. 表達式進行賦值
E.g. int ival = 3.14; // 3.14 converted to int
int *ip;
ip = 0; // the int 0 converted to a null pointer of type int *
4. 指針轉換
指針轉換有兩種類型:任何指針類型都可以轉換成void *,常值0可以轉換成指針類型。數組可以自動轉換成指向數組中第一個元素的指針。
int ia[10]; // array of 10 ints
int* ip = ia; // convert ia to pointer to first element
5. 枚舉類型轉換
枚舉類型可以自動地轉換成int類型。
// point2d is 2, point2w is 3, point3d is 3, point3w is 4
enum Points { point2d = 2, point2w, point3d = 3, point3w };
const size_t array_size = 1024;
// ok: pt2w promoted to int
int chunk_size = array_size * pt2w;
int array_3d = array_size * point3d;
6. Non-const對象轉換成const對象
這種轉換髮生在用一個non-const對象初始化一個const對象。
int i;
const int ci = 0;
//j是i的別名,雖然j是不可變的,但是i可變
const int &j = i; // ok: convert non-const to reference to const int
const int *p = &ci; // ok: convert address of non-const to address of a const
7. 函數參數傳遞以及函數返回值類型轉換
l 隱式類型轉換髮生的場合——類定義
l 顯式轉換使用的操作符
1. static_cast<type>(expression);
build-in類型之間隱式轉換也可以用static_cast來進行顯式轉換。不過一般都在將較大類型轉換成較小類型時使用,告訴編譯器不必在乎精準度的損失。static_cast還有一種用法是將void*轉換成合適類型的指針。static_cast不能進行無關類型(如非基類和子類)指針之間的轉換。
E.g. double d = 97.0;
char ch = static_cast<char>(d); // cast specified to indicate that the conversion is intentional
void* p = &d; // ok: address of any data object can be stored in a void*
// ok: converts void* back to the original pointer type
double *dp = static_cast<double*>(p);
int n;
double *d = static_cast<double *>(&n) //無關類型指針轉換,編譯錯誤
2. const_cast<type>(expression);
用來去掉類型的const或volatile屬性。
3. dynamic_cast<type>(expression);
dynamic_cast將指向基類的指針轉向指向派生類指針。通常這是因爲使用基類的時候需要調用派生類的函數。一般會在基類中使用虛函數,派生類繼承的時候就可以通過繼承,用不同的方法實現該方法。將父類指針指向基類,可能發生錯誤,bad_cast
主要用於類層次間的上行轉換和下行轉換,還可以用於類之間的交叉轉換。在類層次間進行上行轉換時,dynamic_cast和static_cast的效果是一樣的;在進行下行轉換時,dynamic_cast具有類型檢查的功能,比static_cast更安全。
必須要有虛函數。子類繼承父類的虛函數,不同子類實現方式不同。子類也可以複寫父類的虛函數,可以根據類的不同使用不同的函數。
相同基類不同子類之間的交叉轉換。但結果是NULL。
if (Derived *derivedPtr = dynamic_cast<Derived*>(basePtr)) {
// use the Derived object to which derivedPtr points
} else { // BasePtr points at a Base object
// use the Base object to which basePtr points }
void f(const Base &b){
try {
const Derived &d = dynamic_cast<const Derived&>(b);
// use the Derived object to which b referred
} catch (bad_cast) {
// handle the fact that the cast failed
} }
父類指針不能使用dynamic_cast轉換成子類指針,編譯報錯!
4. reinterprete_cast
reinterprete_cast常用來用不同的bit pattern來轉換操作數,這種轉換與機器密切相關。