← C++ Learning Path

C++ V2 · TYPED FOUNDATIONS · 51

Type / Operator / if:C++ 的型別不是註解,而是程式 Contract 的一部分

C++ source 在 process 執行前,先經 compiler 檢查大量型別與語法規則。這一課不是背 int、double,而是建立「expression 先按 operand types 求值,再把結果存進 target type」的精確模型。

Learning outcomes

1. Why now:C++ 在「執行之前」就會拒絕一部分程式

int score = 90;
double average = 87.5;

int invalid = "ninety";
// compile error

JavaScript 常把型別問題留到 runtime;C++ 會把大量 constraints 放進 source-level type system。這不是「比較嚴格」這麼簡單,而是 failure layer 改變了。

2. Mental model:Declaration 同時建立名稱與型別約束

int score = 90;
int
→ declared type

score
→ identifier

90
→ initializer expression

之後 compiler 會用 score 的 type 參與 expression checking、overload resolution 與 conversion。

3. Worked Example A:int division 先發生,再存進 double

int total = 7;
int count = 2;

double average =
    total / count;

std::cout
    << average;
// 3.0

右側 int / int 先得到整數 3,再轉成 double 3.0。左邊宣告 double 不會回頭改寫右側運算規則。

4. Execution trace:Expression Type 要一步一步算

total      : int = 7
count      : int = 2

total/count:
int / int
→ int 3

assign to:
double average
→ 3.0

這種 trace 比「C++ 會自動轉型」更精確,因為 conversion 發生在哪一步會直接影響結果。

5. Worked Example B:明確轉成 floating-point

double average =
    static_cast(
        total
    ) / count;

std::cout
    << average;
// 3.5

現在左 operand 已經是 double,因此 division 進入 floating-point arithmetic。

6. Narrowing:資料「裝得進去」也可能失去資訊

double exact = 3.8;

int truncated =
    static_cast(
        exact
    );

std::cout
    << truncated;
// 3

Conversion 不代表語意一定正確。你仍需知道是否允許 truncation、overflow 或 precision loss。

7. const:把「不應修改」變成 compiler 可檢查的 Constraint

const int passScore = 60;

// passScore = 50;
// compile error

對固定規則使用 const 能把設計意圖轉成編譯期約束。

8. Worked Example C:Condition 是 Typed Expression 的結果

int score = 72;
const int passScore = 60;

const bool passed =
    score >= passScore;

if (passed) {
    std::cout << "Pass
";
} else {
    std::cout << "Fail
";
}

score >= passScore 的結果是 bool;if 消費這個 condition。

9. Rule Ordering:多條件時先定義 Business Boundary

std::string label;

if (score >= 90) {
    label = "Excellent";
} else if (score >= 60) {
    label = "Pass";
} else {
    label = "Fail";
}

如果先寫 score >= 60,90 分也會先進 Pass branch。這不是 compiler error,是 rule ordering logic error。

10. Common mistakes

A. 以為 target type 會改變 expression type

double x = 5 / 2 仍先做 int division。

B. 混淆 assignment 與 comparison

= 與 == 是不同操作;warning 設定可以協助發現可疑寫法。

C. 把 compile 成功等同邏輯正確

60 分邊界寫成 > 60 一樣會成功 build。

D. 無視 input failure

std::cin >> score 失敗會改變 stream state;不能假設所有輸入都合法。

11. Debug evidence:Compiler 與 Runtime Evidence 分開

g++ -std=c++20
    -Wall
    -Wextra
    -pedantic
    main.cpp
    -o grade-analyzer

Compiler diagnostic 回答 source/type 層問題;如果 executable 已成功產生但結果錯,才進 execution trace 與 boundary tests。

12. Guided exercise:預測再 Compile

int a = 5;
int b = 2;

double x = a / b;
double y =
    static_cast(a)
    / b;

先寫 x/y 預測值與每一步 expression type,再實際 compile/run 驗證。

13. Independent exercise:Typed Score Rule

建立 CLI:輸入 score,輸出 Invalid / Fail / Pass / Excellent。規則:

valid: 0..100
Excellent: 90..100
Pass: 60..89
Fail: 0..59

至少測 -1、0、59、60、89、90、100、101。

14. Challenge:Input Stream Failure

int score = 0;

std::cin >> score;

if (!std::cin) {
    // what now?
}

輸入 abc,觀察 stream state。說明這與「score out of range」是不同種類的 validation failure。

Project checkpoint:CLI Grade Analyzer · Typed Core v1

stdin
  ↓ parse typed input
int score
  ↓ validate range
0..100
  ↓ classify
Excellent / Pass / Fail
  ↓
stdout

這一版只處理一筆 score;52 會把規則拆成 function 並處理多筆。

15. Vocabulary / Summary

16. Further reading

Knowledge check · Mastery

  1. 解釋 double x = 5 / 2; 為何是 2.0。
  2. 完成 8 個 score boundary cases。
  3. 區分 input parse failure、range failure 與 logic error。
  4. 完成頁面下方 C++ compile/trace practice。