一个表达式里混着不同类型怎么办?算术运算时低类型自动"爬楼梯"升成高类型(隐式);赋值时高类型装进低盒子会"截断";不想等编译器猜,就强制转换显式下指令。教材实例04、05 正好一隐一显。
一、隐式转换:楼梯只能向上爬
规则:混算时,"小"类型自动转成"大"类型,然后运算。
bool → char/short → int → long long → float → double
3 + 2.5:int 的 3 升成 double →3.0 + 2.5→5.5'A' + 1:char 的 'A' 升成 int →65 + 1→66(int)a + 1.5(a 是 int):a 升 double,结果类型是 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 风格
(double)a:简单粗暴,任何地方都能转,转错了编译器不管 static_cast:写起来长,但编译器帮你检查这次转换合不合理——长一点是买保险
教材现阶段用 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——晚了一步。括号加在哪、转换在除法之前还是之后,结果天差地别。
六、常见误区
- "隐式转换会自动发生在我想要的所有地方"——只发生在算术混算和赋值两类时机,且方向固定(算术向上、赋值向左)。时机和方向错了就得出错结果。
- "
int x = 3.9会四舍五入成 4"——砍成 3,往零的方向。 - "
(double)(a / b)和(double)a / b一样"——完全不同:前者转换"除完的结果"(晚了),后者转换"被除数"(及时)。转换位置决定成败。 - "
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)。- ☐ 3.4 判断左值与右值(下一节)