3.7 型態轉換(隱性與顯性)
有時候我們會在不同型態之間轉換數值,例如把一個 bool 當成 int 來用。C++ 有兩種轉換方式:編譯器自動幫你做的(隱性轉換),以及你自己動手指定的(顯性轉換)。
¶隱性轉換(Implicit Conversion)
C++ 會在某些情況下自動幫你轉換型態,稱為隱性轉換——你沒有明講,編譯器自己做。方便歸方便,但有時會悄悄造成意外,所以要知道它「什麼時候會發生」。下面把常見的情況一條一條列出來:
① bool → int:布林值當數字用
當一個 bool 出現在需要數字的地方,true 會變成 1、false 會變成 0:
bool b = true;
int i = b; // true → 1
cout << i << endl; // 輸出:1
其實你早就用過這個規則——cout << (3 > 2); 會印出 1,就是因為比較的結果是 bool,輸出時被自動轉成了 int。
那「需要數字的地方」具體是指哪些?把 bool → int 的發生時機一條條列出來:
- 算術運算的運算元:
+、-、*、/、%碰到布林值,先把它變成1或0再算——例如(3 > 2) + (5 > 1)的值是2。 - 和整數比較大小:例如
(a < b) < c會先把a < b的結果變成0或1,再拿去和c比——3.3 講過「比較運算子不能連寫」,根源就在這裡。 - 指派給整數變數:
int i = b;。 - 用
cout輸出:印出來是1/0(除非開了 3.1 的boolalpha)。
② int → bool:數字當條件用
反過來,當一個數字被當成布林值,0 會變成 false,任何非 0 的值都變成 true。int → bool 的發生時機:
if/else if小括號裡的運算式(3.5)——放進去的不是布林值時,會被自動轉成布林值。之後第四單元學到的while迴圈,條件也適用同一規則。- 邏輯運算子
&&、||、!的運算元(3.3)。 - 指派給
bool變數:
bool b1 = 0; // 0 → false
bool b2 = 5; // 非 0 → true(不是變成 5,而是 true)
cout << boolalpha << b1 << " " << b2 << endl; // 輸出:false true
這也是為什麼 if (n) 等同於 if (n != 0)。
③ int → long long:和更大的整數型態一起運算
當 int 和 long long 放在同一個算術運算裡,C++ 會先把 int 轉成 long long,再用 long long 計算:
int a = 100000;
long long b = 100000;
cout << a * b << endl; // a 先轉成 long long,乘法用 long long 算
這個規則很常用在避免整數溢位。重點是:運算開始前,至少要有一邊已經是 long long,整段運算才會改用 long long。
隱性轉型時機一覽
| 方向 | 什麼時候發生 | 規則 |
|---|---|---|
int → bool |
if/else if 的條件、邏輯運算(&&、||、!)的運算元、指派給 bool 變數 |
非 0 → true、0 → false |
bool → int |
算術運算的運算元、和整數比較大小、指派給整數變數、cout 輸出 |
true → 1、false → 0 |
int → long long |
和 long long 一起做算術運算、指派給 long long 變數 |
數值不變,但改用 long long 的範圍計算或儲存 |
¶顯性轉換(Explicit Conversion / Cast)
有時候我們想自己指定要轉成什麼型態,這叫強制轉型(cast),寫法是在值前面加一個 (目標型態):
(目標型態) 值
一個很實用的例子是避免整數溢位。還記得第二單元說過,兩個 int 相乘、結果太大時會溢位嗎?我們可以在相乘前,先把其中一個強制轉成 long long,讓整段運算改用 long long 進行:
int x = 100000, y = 100000;
long long wrong = x * y; // ✗ x * y 先以 int 相乘 → 溢位、結果錯誤
long long ok = (long long)x * y; // ✓ x 先轉成 long long,整段用 long long 算
cout << ok << endl; // 輸出:10000000000
¶動手試試看
寫一個程式,輸入一個整數 n,把它直接指派給一個 bool 變數,再用 boolalpha 印出來。試試看輸入 0、5、-3 各會印出什麼,並想想為什麼。