🔷 第三章 运算符与表达式
📄 一句话概括

一个表达式里混着不同类型怎么办?算术运算时低类型自动"爬楼梯"升成高类型(隐式);赋值时高类型装进低盒子会"截断";不想等编译器猜,就强制转换显式下指令。教材实例04、05 正好一隐一显。

一、隐式转换:楼梯只能向上爬

规则:混算时,"小"类型自动转成"大"类型,然后运算。

bool → char/short → int → long long → float → double

为什么只许向上? 向上扩容不丢信息(int 的任何值 double 都装得下);向下缩容可能丢。编译器不敢替你做丢信息的决定——所以"楼梯只上不下"是隐式的全部规则。

2.4.1 的谜底揭晓:5 / 2 两个都是 int,谁也不用升 → 整数除法得 2;5.0 / 2 有一个 double → int 的 2 升 double → 浮点除法得 2.5。类型转换在运算前发生,这就是"想要小数至少一个是浮点"的原理。

二、赋值时的反向:静悄悄的截断

把高类型的值装进低类型的盒子(窄化),编译器允许,但会砍:

int x = 3.9;        // x = 3:小数被砍掉(不是四舍五入!)
int y = 2.99e9;     // 溢出:超出 int 范围,值没保证
double d = 5;       // 安全:向上装,d = 5.0

砍的方式:往零的方向砍(3.9→3,-3.9→-3)。不报错——2.6 小结的"不报错的更危险"又添一员。

这个机制同时解释了 3.1.1 的坑:int a = 7, b = 2; double avg = a / b; —— 除法先在 int 世界做完(得 3),再把 3 装进 avg。顺序是:先转换参与运算 → 运算 → 结果再转成左边的类型。顺序错了,救不回来。

三、强制转换:显式下指令

不想等隐式的脾气,就自己点名。两种写法都要认识:

// C 风格(教材用这种):(类型)值
double avg = (double)total / n;

// C++ 现代写法:static_cast<类型>(值)
double avg = static_cast<double>(total) / n;

教材现阶段用 C 风格,你写作业跟教材保持一致即可;读别人代码时认得出 static_cast 就行。

转换的"作用范围"很关键:(double)total / n 只把 total 变成 double,n 不变——但够用了,因为除法有一个 double 参与,另一个自动升(隐式规则接手)。不用写成 (double)total / (double)n。

四、教材实例04、05 的思路复现

实例04(隐式转换):

#include <iostream>
using namespace std;

int main() {
    char c = 65;              // 'A'
    cout << c + 1 << endl;    // 66:char 升 int(隐式)
    cout << (char)(c + 1) << endl;  // B:再强转回 char 就显示字母

    int x = 3, y = 2;
    cout << x / y << endl;    // 1:都 int,整数除法
    cout << x / 2.0 << endl;  // 1.5:2.0 让 x 隐式升 double
    return 0;
}

实例05(强制转换):

int total = 17, n = 2;
cout << total / n << endl;          // 8:先整除,救不回
cout << (double)total / n << endl;  // 8.5:先转再除
cout << total / (double)n << endl;  // 8.5:转另一边也行

规律总结(口诀):算术看最高(结果类型跟最高的走)· 赋值看左边(装不进就截)· 想保小数先转一个。

五、30 秒实验

int a = 10, b = 3;
cout << a / b << endl;              // 3
cout << (double)a / b << endl;      // 3.33333
cout << (double)(a / b) << endl;    // 3!!括号位置决定生死

看到什么算成功:3 3.33333 3。第三行是本节最重要的实验:(double)(a / b) 先做整数除法得 3,再转 double——晚了一步。括号加在哪、转换在除法之前还是之后,结果天差地别。

六、常见误区

  1. "隐式转换会自动发生在我想要的所有地方"——只发生在算术混算和赋值两类时机,且方向固定(算术向上、赋值向左)。时机和方向错了就得出错结果。
  2. "int x = 3.9 会四舍五入成 4"——砍成 3,往零的方向。
  3. "(double)(a / b) 和 (double)a / b 一样"——完全不同:前者转换"除完的结果"(晚了),后者转换"被除数"(及时)。转换位置决定成败。
  4. "static_cast 是新语法没必要学"——先会 C 风格没错,但要认识 static_cast(工程代码里是主流),别见了当生词。
自测四问(点开对答案) 1. `'A' + 1` 的类型和值?——int,66(char 升 int)。 2. `int x = 7.8;` x 是多少?——`7`(向零截断)。 3. `a=5, b=2`,`(double)a / b` 与 `a / (double)b` 各是多少?——都是 `2.5`(一边转了另一边自动升)。 4. `(int)3.9 + 1` 和 `(int)(3.9 + 1)` 各是多少?——`4` 和 `4`(碰巧同值,过程不同:前者 3+1,后者 4.9 截成 4)。

相关笔记