类型转换详解

← 返回 MOC


隐式转换(自动转换)

算术转换(表达式中)

混合类型参与运算时,C++ 会将较小的类型提升为较大的类型,再做运算:

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

整型 + 浮点 → 浮点:

int i = 3;
double d = 1.5;
auto result = i + d;   // result 是 double,值为 4.5

bool / char / short 参与算术时会先整型提升int,再计算。

赋值转换

把右侧值赋给左侧变量时,自动转为目标类型。可能丢失信息

int i   = 3.9;     // i = 3,小数部分截断(不是四舍五入!)
float f = 1e300;   // 超出 float 范围,结果未定义
bool b  = -5;      // b = true(非零即 true)
char c  = 257;     // 溢出,结果依赖实现(通常回绕为 1)

C++11 的 {} 初始化会拒绝窄化转换(直接报错):

int x{3.9};   // 编译错误:narrowing conversion

函数参数转换

传参时也会发生同样的隐式转换:

void foo(double x);
foo(3);    // int 3 → double 3.0,自动提升

显式转换(强制转换)

C 风格(不推荐)

(int)3.9        // 结果 3
(double)7 / 2   // 结果 3.5(先转再除)

C++ 函数风格

int(3.9)        // 结果 3,只是形式上像函数调用

C++ 推荐:static_cast<>

static_cast<int>(3.9)       // 3
static_cast<double>(7) / 2  // 3.5

为什么推荐 static_cast<>

  • 在代码里视觉上很显眼,容易 grep 查找
  • 只做编译期合法的转换,不会绕过类型系统
  • 比 C 风格更安全,能被代码审查工具识别

四种具名转换(进阶)

C++ 还提供了四种用途更精确的转换,了解即可:

转换用途
static_cast<T>编译期类型转换(最常用)
const_cast<T>去掉 / 加上 const 修饰
reinterpret_cast<T>底层重新解释比特(危险,少用)
dynamic_cast<T>运行期多态向下转型(需虚函数,后续章节讲)

常见陷阱

// 陷阱 1:整数除法
int a = 7, b = 2;
double r = a / b;       // r = 3.0,不是 3.5!除法已经发生在整型
double r2 = (double)a / b;  // r2 = 3.5,先转再除
 
// 陷阱 2:截断不是四舍五入
int i = (int)3.9;   // i = 3,不是 4
 
// 陷阱 3:无符号整数下溢
unsigned int u = 0;
u - 1;   // 结果是 UINT_MAX(4294967295),不是 -1
 
// 陷阱 4:有符号溢出(未定义行为!)
int x = INT_MAX;
x + 1;   // 未定义行为,不保证回绕

上溢与下溢