当前位置: 首页 > news >正文

C++ 四种类型转换

🚀 C++四种类型转换详解:static_cast、dynamic_cast、const_cast、reinterpret_cast
📅 更新时间:2025年8月13日
🏷️ 标签:C++ | 现代C++ | 类型系统 | RTTI | 类型转换

文章目录

  • 📖 前言
  • 🔍 一、核心概念与对比
  • 📝 二、static_cast
    • 1.static_cast正确用法
    • 2.static_cast错误用法
  • 📝 三、dynamic_cast
    • 1.dynamic_cast 正确用法
    • 2.dynamic_cast 错误用法
  • 📝 四、const_cast
    • 1.const_cast 正确用法
    • 2.const_cast 错误用法
  • 📝 五、reinterpret_cast
    • 1.reinterpret_cast 正确用法
    • 2.reinterpret_cast 错误用法
    • ✅ 速记
  • 🧭 总结与选型建议

📖 前言

类型转换C++ 类型系统的锋利工具。用得好,代码安全又优雅;用不好,未定义行为与线上事故分分钟找上门。本文系统梳理 C++ 四种显式类型转换的语义边界、使用场景与陷阱,并配以可运行示例与纠错建议。

用对转换“刀法”,用最小的权限做正确的事。


🔍 一、核心概念与对比

  • static_cast编译期 语义转换,适合数值/枚举/指针的“已知安全”变换与上行/受控下行。

  • dynamic_cast运行期 带 RTTI 检查的安全下行/交叉转换,失败返回 nullptr/抛异常。

  • const_cast:仅移除/添加顶层 const/volatile 限定,不做对象重解释。

  • reinterpret_cast:位级重解释,几乎不受约束,但最危险,谨慎用在极少数底层场景。
    优先选“更安全”的转换:dynamic_cast > static_cast > const_cast > reinterpret_cast(非严格可替换关系)。

  • C++ 强制类型转换运算符的用法如下:
    强制类型转换运算符 <要转换到的类型> (待转换的表达式)
    例如:

double d = static_cast <double> (3*5);  //将 3*5 的值转换成实数

下面分别介绍四种强制类型转换运算符


📝 二、static_cast

static_cast 用于进行比较自然低风险的转换,如整型浮点型字符型之间的互相转换。另外,如果对象所属的类重载了强制类型转换运算符 T(如 T 是 int、int* 或其他类型名),则 static_cast 也能用来进行对象到 T 类型的转换。

static_cast 不能用于在不同类型的指针之间互相转换,也不能用于整型和指针之间的互相转换,当然也不能用于不同类型的引用之间的转换 因为这些属于风险比较高的转换 !!!

1.static_cast正确用法

下面是会用到static_cast的地方

  • 数值显示转换
double t=3.14;
int n=t;//隐式转换  不便于排查
int n=static_cast<int>(t);//显示转换 此时n=3
  • 选择函数重载
class A
{
public:operator int(){return 1;}operator double(){return 3.14;}
};int main()
{A n;int x=n;//x=1 隐式转换double x=n;//x=3.14 隐式转换int x=static_cast<int>(n);//x=1 显式转换int x=static_cast<double>(n);//x=3.14 显式转换return 0;
}

同时提供多个转换运算符在某些表达式中可能引发二义性,此时用 static_cast<目标类型>(n) 明确指定类型更便于阅读

  • 枚举与整数互转(值域需自查)
enum class Color { Red = 1, Green = 2 };
int v = static_cast<int>(Color::Red);    // 1
Color c = static_cast<Color>(v);         // 前提:v 落在有效枚举值范围
  • 继承层次的上行转换(派生 → 基类,安全;指针/引用均可)
struct Base { virtual ~Base() = default; };
struct Derived : Base {};Derived d;
Base* pb = static_cast<Base*>(&d);   // OK:上行
Base& rb = static_cast<Base&>(d);    // OK:上行
// 下行若不确定真实类型,请使用 dynamic_cast 以避免未定义行为

2.static_cast错误用法

  • 不同类型的指针无法转换
int n = 1;
int* p = &n;
char* x = static_cast<char*>(p);//错误 不同类型指针无法转换
  • 指针与整型之间的转换
int n = 1;
int* p = static_cast<int*>(n);//错误---int a = 1;
int* p = &a;
int n = static_cast<int>(p);//错误整型与指针类型之间无法转换
  • 多态下行转换使用 static_cast(风险高,可能未定义行为)
struct Base { virtual ~Base() = default; };
struct Derived : Base {};Base* pb = new Base;                     // 实际不是 Derived
Derived* pd = static_cast<Derived*>(pb); // 错误做法:类型不对将导致 UB
// 正确:使用 dynamic_cast<Derived*>(pb) 并判断是否为 nullptr

进一步说明:

  • 上行(派生→基类)总是安全且可隐式;下行(基类→派生)只有当对象真实类型就是该派生类时才安全。
  • static_cast 下行不做运行期检查,类型不符会产生未定义行为(UB)。
  • dynamic_cast 需要基类含有虚函数,指针失败时返回 nullptr,引用失败时抛出 std::bad_cast

什么时候用哪个?

  • 已经能“证明”对象真实类型是 Derived(例如对象就是 Derived 构造的):可用 static_cast 下行。
  • 无法确定真实类型或来自多态接口:使用 dynamic_cast 并检查结果。

示例:已知安全的下行(来源明确是 Derived)

Derived d;
Base* pb_ok = &d;                         // 上行
Derived* pd_ok = static_cast<Derived*>(pb_ok); // 下行:安全

示例:运行期检查的下行(不确定来源)

Base b;
Base* pb_unknown = &b;                    // 真实类型不是 Derived
if (auto pd2 = dynamic_cast<Derived*>(pb_unknown)) {// ... 使用 pd2
} else {// 不是 Derived,避免 UB
}

📝 三、dynamic_cast

dynamic_cast 用于多态类型间的安全下行/交叉转换,依赖 RTTI(运行期类型信息)。
dynamic_cast 是通过“运行时类型检查”来保证安全性的

1.dynamic_cast 正确用法

  • 多态下行:指针转换后判空
struct Base { virtual ~Base() = default; };
struct Derived : Base { void foo() {} };void use(Base* pb) {if (auto pd = dynamic_cast<Derived*>(pb)) {pd->foo();               // 成功:pb 真实指向 Derived} else {// 失败:pb 不是 Derived,避免未定义行为}
}int main() {Derived d; Base b;use(&d); // 成功路径use(&b); // 失败路径(pd 为 nullptr)
}

注意:

  • 基类需含有虚函数(开启 RTTI);否则编译不通过。
  • 指针转换失败返回 nullptr;引用失败会抛 std::bad_cast
  • 仅用于多态体系内的安全下行/交叉转换。

2.dynamic_cast 错误用法

  • 用在非多态基类(没有任何虚函数)
struct Base {};              // 非多态
struct Derived : Base {};
Base* pb = new Base;
auto pd = dynamic_cast<Derived*>(pb); // 错:Base 非多态,编译失败
  • 引用下行失败会抛异常(需显式处理)
struct Base { virtual ~Base() = default; };
struct Derived : Base {};
Base b;
try {Derived& rd = dynamic_cast<Derived&>(b); // 失败 => 抛 std::bad_cast
} catch (const std::bad_cast&) {// 处理失败
}

📝 四、const_cast

const_cast 仅用于添加/移除顶层 const/volatile 限定,不改变对象的实际类型。

1.const_cast 正确用法

  • 恢复非常量对象的非常量性(原对象本身不是 const)
void takes_int_ptr(int* p);
int x = 42;
const int* cp = &x;                      // 顶层 const
takes_int_ptr(const_cast<int*>(cp));     // OK:对象本身非 const

2.const_cast 错误用法

  • 去 const 后修改“本来就是 const”的对象(未定义行为)
const int y = 0;
int* py = const_cast<int*>(&y);
*py = 1; // 错:修改真正的 const 对象 => UB

📝 五、reinterpret_cast

reinterpret_cast 进行位级重解释,几乎不做语义保证。谨慎,仅限底层场景。

1.reinterpret_cast 正确用法

  • 只做字节级观察(读取对象表示),不跨类型语义访问
int v = 0x12345678;
unsigned char* bytes = reinterpret_cast<unsigned char*>(&v);
// 仅查看/拷贝字节,不把它当作其他类型解引用访问

2.reinterpret_cast 错误用法

  • 将不相关类型指针互转后解引用(违反别名/对齐,UB)
double* dp = nullptr;
int* ip = reinterpret_cast<int*>(dp);
*ip = 1; // 错:未定义行为

✅ 速记

  • 能隐式就隐式;需显式先 static;多态下行用 dynamic;改限定符找 const;位级重解释才用 reinterpret(慎用)。

🧭 总结与选型建议

转换主要用途运行期检查常见正确用法典型错误用法/风险
static_cast数值/枚举互转;继承上行;已知安全的受控下行避免整除、选择重载、枚举↔整型、派生→基类不相关指针互转;指针↔整型;不确定类型的下行(UB)
dynamic_cast多态下行/交叉转换是(需虚函数)指针判空后使用;引用用 try-catch 捕获失败用在非多态基类;无检查的错误假设
const_cast添加/移除顶层 const/volatile将“非常量对象的 const 视图”复原去 const 后修改“本为 const”的对象(UB)
reinterpret_cast位级重解释/底层操作仅做字节观察或与平台相关的低层用途跨不相关类型解引用(别名/对齐导致 UB)

简要建议

  • 能否不转换;能隐式就隐式。
  • 需要显式转换,优先 static_cast;多态下行用 dynamic_cast。
  • 仅改限定符用 const_cast;位级重解释最后再考虑,且尽量局部化、加注释与断言。
http://www.dtcms.com/a/330101.html

相关文章:

  • el-table合并相同名称的列
  • 朝花夕拾(三)---------中文分词利器jieba库的详解与实战应用(python)
  • 洛谷 小 Y 拼木棒 贪心
  • 函数对象(仿函数)适配器
  • 《量子雷达》第2章 从量子信息到量子雷达 预习2025.8.13
  • 工业视觉检测中的常见的四种打光方式
  • Java 导出word 实现表格内插入图表(柱状图、折线图、饼状图)--可编辑数据
  • java反射与泛型的简单知识和应用
  • 【KO】Android 网络相关面试题
  • 326. 3 的幂
  • 不用费心备份操作的实验记录本
  • VUE基础笔记
  • 【AI学习100天】Day07 加入AI社区,通往AGI之路
  • C# 反射和特性(获取Type对象)
  • 【C#】利用数组实现大数数据结构
  • Spring Cloud系列— Alibaba Sentinel限流
  • Pycharm现有conda环境有对应env,但是添加后没反应
  • 《人形机器人的觉醒:技术革命与碳基未来》——生物混合肌肉:技术原理和进展、比较优势和不足、材料技术要求及材料限制
  • 递归函数与 lambda 函数:用法详解与实践
  • Synchronized锁的使用方式
  • three.js学习记录(鼠标控制)
  • Linux 计划任务
  • 【web站点安全开发】任务3:网页开发的骨架HTML与美容术CSS
  • STM32学习笔记10—DMA
  • JSON索引香港VPS:高效数据处理的完美解决方案
  • JDK17下载与安装图文教程(保姆级教程)
  • 《汇编语言:基于X86处理器》第13章 复习题和编程练习
  • VerIF
  • 【R语言】RStudio 中的 Source on Save、Run、Source 辨析
  • [系统架构设计师]系统架构基础知识(一)