語法書 / AA 競程語法書 上冊 / 第三單元 / 型態轉換(隱性與顯性)

3.7 型態轉換(隱性與顯性)

有時候我們會在不同型態之間轉換數值,例如把一個 bool 當成 int 來用。C++ 有兩種轉換方式:編譯器自動幫你做的(隱性轉換),以及你自己動手指定的(顯性轉換)

隱性轉換(Implicit Conversion)

C++ 會在某些情況下自動幫你轉換型態,稱為隱性轉換——你沒有明講,編譯器自己做。方便歸方便,但有時會悄悄造成意外,所以要知道它「什麼時候會發生」。下面把常見的情況一條一條列出來:

boolint:布林值當數字用

當一個 bool 出現在需要數字的地方,true 會變成 1false 會變成 0

bool b = true;
int i = b;          // true → 1
cout << i << endl;  // 輸出:1

其實你早就用過這個規則——cout << (3 > 2); 會印出 1,就是因為比較的結果是 bool,輸出時被自動轉成了 int

那「需要數字的地方」具體是指哪些?把 boolint發生時機一條條列出來:

  • 算術運算的運算元+-*/% 碰到布林值,先把它變成 10 再算——例如 (3 > 2) + (5 > 1) 的值是 2
  • 和整數比較大小:例如 (a < b) < c 會先把 a < b 的結果變成 01,再拿去和 c 比——3.3 講過「比較運算子不能連寫」,根源就在這裡。
  • 指派給整數變數int i = b;
  • cout 輸出:印出來是 10(除非開了 3.1boolalpha)。

intbool:數字當條件用

反過來,當一個數字被當成布林值,0 會變成 false,任何非 0 的值都變成 trueintbool發生時機

  • ifelse 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)

intlong long:和更大的整數型態一起運算

intlong 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

隱性轉型時機一覽

方向 什麼時候發生 規則
intbool ifelse if 的條件、邏輯運算(&&||!)的運算元、指派給 bool 變數 0true0false
boolint 算術運算的運算元、和整數比較大小、指派給整數變數、cout 輸出 true1false0
intlong 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 印出來。試試看輸入 05-3 各會印出什麼,並想想為什麼。