在C++中,类型转换是将一个类型的值转换为另一个类型的操作,分为隐式类型转换(编译器自动完成)和显式类型转换(程序员主动指定)两类。
一、隐式类型转换(自动转换)
编译器在特定场景下自动触发的转换,无需程序员干预,通常发生在“类型兼容且安全”的场景中。
1. 基础数据类型的隐式转换(小范围→大范围)
当“小类型”赋值给“大类型”时,编译器自动转换(无数据丢失):
#include<iostream>usingnamespacestd;intmain(){// 1. char → int(小整数类型→大整数类型)charc='a';// 'a'的ASCII值是97inti=c;// 隐式转换:c的97自动转为int类型cout<<"i = "<<i<<endl;// 输出:97// 2. int → double(整数→浮点数)intnum=10;doubled=num;// 隐式转换:10自动转为10.0cout<<"d = "<<d<<endl;// 输出:10// 3. 表达式中的隐式转换(混合类型运算)inta=5;doubleb=2.5;doubleres=a+b;// a(int)隐式转为double,结果为7.5cout<<"res = "<<res<<endl;// 输出:7.5return0;}2. 类的隐式转换(单参数构造函数/类型转换运算符)
- 单参数构造函数:允许用该参数类型的值“隐式构造”类对象;
- 类型转换运算符:允许类对象“隐式转换”为其他类型。
#include<iostream>usingnamespacestd;classMyInt{private:int_val;public:// 单参数构造函数:允许int→MyInt的隐式转换MyInt(intval):_val(val){}// 类型转换运算符:允许MyInt→int的隐式转换operatorint()const{return_val;}voidshow()const{cout<<"MyInt: "<<_val<<endl;}};intmain(){// 1. int → MyInt(单参数构造函数的隐式转换)MyInt mi=100;// 等价于 MyInt mi(100),隐式转换mi.show();// 输出:MyInt: 100// 2. MyInt → int(类型转换运算符的隐式转换)intnum=mi;// 隐式转换为intcout<<"num = "<<num<<endl;// 输出:100return0;}二、显式类型转换(强制转换)
程序员通过转换操作符主动指定的转换,用于“编译器不会自动转换”的场景(可能存在风险)。C++提供4种显式转换: static_cast 、 dynamic_cast 、 const_cast 、 reinterpret_cast 。
1. static_cast :静态类型转换(编译期检查)
用于相关类型的转换(如基本类型、类的向上/向下转型),编译期检查合法性,但不保证运行时安全。
#include<iostream>usingnamespacestd;intmain(){// 1. 基本类型转换(大→小,可能丢失数据)doubled=3.14;inti=static_cast<int>(d);// 显式转换:3.14→3cout<<"i = "<<i<<endl;// 输出:3// 2. 类的向上转型(子类→父类,安全)classBase{};classDerived:publicBase{};Derived*d_ptr=newDerived();Base*b_ptr=static_cast<Base*>(d_ptr);// 向上转型,安全// 3. 类的向下转型(父类→子类,不安全,编译期不检查)Base*b=newBase();Derived*d2=static_cast<Derived*>(b);// 编译通过,但运行时可能出错deleted_ptr;deleteb;return0;}2. dynamic_cast :动态类型转换(运行期检查)
仅用于类的指针/引用,主要用于向下转型,运行期检查类型兼容性,失败时返回 nullptr (指针)或抛出异常(引用)。
#include<iostream>usingnamespacestd;classBase{public:virtualvoidshow()const{cout<<"Base"<<endl;}// 虚函数,支持多态};classDerived:publicBase{public:voidshow()constoverride{cout<<"Derived"<<endl;}};intmain(){Base*b1=newDerived();// 父类指针指向子类对象Base*b2=newBase();// 父类指针指向父类对象// 1. 安全的向下转型(b1指向子类)Derived*d1=dynamic_cast<Derived*>(b1);if(d1){d1->show();// 输出:Derived}// 2. 不安全的向下转型(b2指向父类)Derived*d2=dynamic_cast<Derived*>(b2);if(!d2){cout<<"d2 is nullptr"<<endl;// 输出:d2 is nullptr}deleteb1;deleteb2;return0;}3. const_cast :常量性转换
用于移除/添加 const 属性,仅能用于指针/引用,不能用于普通变量。
#include<iostream>usingnamespacestd;intmain(){constintnum=10;// 移除const(仅当原变量不是const时安全)int*p=const_cast<int*>(&num);*p=20;// 未定义行为(原num是const,修改会导致错误)cout<<"num = "<<num<<endl;// 可能输出10(编译器优化)// 安全场景:原变量不是const,指针被const修饰intval=5;constint*cp=&val;int*np=const_cast<int*>(cp);*np=15;cout<<"val = "<<val<<endl;// 输出:15return0;}4. reinterpret_cast :重新解释转换
用于不相关类型的转换(如指针→整数、不同类型指针互转),是最“暴力”的转换,仅重新解释二进制,不做类型检查,风险极高。
#include<iostream>usingnamespacestd;intmain(){// 1. 指针→整数inta=10;int*p=&a;uintptr_t addr=reinterpret_cast<uintptr_t>(p);// 指针转为无符号整数cout<<"addr = "<<addr<<endl;// 输出指针的地址值// 2. 不同类型指针互转doubled=3.14;int*dp=reinterpret_cast<int*>(&d);// double指针→int指针// *dp的值是无意义的(二进制被重新解释)cout<<"*dp = "<<*dp<<endl;return0;}三、隐式 vs 显式转换的区别
| 特性 | 隐式类型转换 | 显式类型转换 |
|---|---|---|
| 触发方式 | 编译器自动完成 | 程序员主动指定(如(type)var或static_cast) |
| 安全性 | 通常安全(小范围→大范围、兼容类型转换) | 可能不安全(大范围→小范围、类型不兼容时易溢出/截断) |
| 适用场景 | 类型兼容的自动转换(如int→double) | 编译器不自动转换的场景(如double→int强制取整) |
| 可读性 | 不明显,需熟悉语言内置转换规则 | 明确可见,直接体现代码主动转换意图 |