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

c++的四种类型转换(static_cast,reinterpret_cast,const_cast,dynamic_cast)详解和代码示例

1. static_cast

1.1 底层原理

  • 编译器在 编译阶段 完成类型转换的检查与生成转换代码
  • 对基本类型,可能直接插入指令(如 mov + 类型扩展/截断指令)
  • 对类层次结构中的指针转换(上行或下行),会按照已知的内存布局调整指针偏移量

1.2 常用场景

  1. 数值类型转换

    double d = static_cast<double>(42); // int -> double
    
  2. 枚举与整数转换

    enum Color { Red, Green, Blue };
    Color c = static_cast<Color>(1);
    
  3. 类层次中的安全上行转换

    Base* b = static_cast<Base*>(derivedPtr);
    
  4. 已知安全的向下转型(无运行时检查)

    Derived* d = static_cast<Derived*>(b); // 需确保 b 真指向 Derived
    

1.3 陷阱

  • 向下转型若对象真实类型不匹配,会导致 未定义行为
  • 不会去掉 const,需要配合 const_cast 才能同时做类型+修饰符的转换

2. dynamic_cast

2.1 底层原理

  • 依赖 RTTI(运行时类型信息),编译器会为 有虚函数的类 生成 虚表指针(vptr)
  • 转换时,dynamic_cast 会沿类层次查找,判断类型是否匹配
  • 指针转换失败返回 nullptr,引用转换失败抛 std::bad_cast

2.2 常用场景

  1. 多态向下转型(安全检查)

    if (auto d = dynamic_cast<Derived*>(basePtr)) {d->doSomething();
    }
    
  2. 交叉转换(Cross cast)

    • 用于多继承时,从一个基类跨到另一个基类
  3. 运行时类型判别

    if (dynamic_cast<Derived*>(b)) { /* 是 Derived */ }
    

2.3 陷阱

  • 必须是多态类(至少一个虚函数)
  • RTTI 关闭(-fno-rtti)时不可用
  • 性能比 static_cast 慢(运行时遍历虚表)

3. const_cast

3.1 底层原理

  • 编译器在语义分析阶段直接去掉 const / volatile 标志,不改变对象内存布局
  • 运行时不会生成额外指令(除了调用接口时参数类型变化)

3.2 常用场景

  1. 调用非 const 接口

    void modify(int* p);
    const int x = 10;
    modify(const_cast<int*>(&x)); // 不安全
    
  2. 配合遗留 API(C 接口)

    void legacy(char* buf);
    const char* s = "Hello";
    legacy(const_cast<char*>(s)); // 若修改字面量则 UB
    

3.3 陷阱

  • 对原本是常量的对象去掉 const 并修改,属于 未定义行为
  • 安全的前提:对象底层确实是可修改的

4. reinterpret_cast

4.1 底层原理

  • 编译器在 编译阶段 直接重解释指针或整数的二进制位,不做语义检查
  • 常用于类型系统之外的底层内存操作

4.2 常用场景

  1. 指针类型之间的转换

    void* p = malloc(4);
    int* ip = reinterpret_cast<int*>(p);
    
  2. 整数 ↔ 指针

    intptr_t addr = reinterpret_cast<intptr_t>(ip);
    
  3. 硬件寄存器访问 / 网络字节解析

    uint32_t val = 0x12345678;
    unsigned char* bytes = reinterpret_cast<unsigned char*>(&val);
    

4.3 陷阱

  • 结果强依赖平台字节序与内存对齐
  • 在不同类型之间转换后访问可能破坏严格别名规则(strict aliasing)

工程使用建议

  • 优先级推荐

    1. static_cast:最安全,首选
    2. dynamic_cast:运行时安全检查(必要时用)
    3. const_cast:仅在确实需要去掉 const 时用
    4. reinterpret_cast:除非底层操作,尽量避免
  • 组合使用:如果要同时做类型和 const 修饰符转换,建议分步:

    Derived* d = static_cast<Derived*>(const_cast<Base*>(cb));
    
  • 性能考虑:频繁调用 dynamic_cast 会影响性能,尤其在实时系统(如 SLAM)中

  • 代码可维护性:过多 reinterpret_cast 会让代码难以理解且难以移植


总结对比

转换方式编译期/运行期主要用途是否类型检查能否去 const安全性
static_cast编译期基本类型转换、已知安全的类层次转换编译期检查较安全
dynamic_cast运行期多态类的安全向下转型运行期检查安全(失败返回 nullptr)
const_cast编译期添加/移除 const/volatile编译期检查视情况而定
reinterpret_cast编译期低级别强制转换(指针、整数)编译期弱检查危险

实战应用示例

下面 6 工程场景的应用示例,涵盖从普通类型到多态类、底层内存操作以及和 C API 交互的情况,大家可以在 SLAM、驱动、图形等 C++ 项目时都能直接套用,直接进行更改,方便快捷。


示例 1:static_cast — 传感器数据类型转换

在 SLAM 系统中,IMU 数据通常是 int16_t(原始寄存器值),需要转换为 double(物理量)。

#include <iostream>
#include <cstdint>
using namespace std;struct IMUDataRaw { int16_t acc_x; };int main() {IMUDataRaw raw{ 16384 }; // 假设这是 1gdouble acc_x_g = static_cast<double>(raw.acc_x) / 16384.0; cout << "Acceleration X: " << acc_x_g << " g" << endl;
}

示例 2:dynamic_cast — 多态消息解码

SLAM 系统接收统一基类的消息,需要根据实际类型解析。

#include <iostream>
#include <memory>
using namespace std;struct MsgBase { virtual ~MsgBase() = default; };
struct LidarMsg : MsgBase { void process() { cout << "Process Lidar\n"; } };
struct IMUMsg : MsgBase { void process() { cout << "Process IMU\n"; } };void handleMsg(shared_ptr<MsgBase> msg) {if (auto lidar = dynamic_cast<LidarMsg*>(msg.get())) {lidar->process();} else if (auto imu = dynamic_cast<IMUMsg*>(msg.get())) {imu->process();} else {cout << "Unknown message\n";}
}int main() {handleMsg(make_shared<LidarMsg>());handleMsg(make_shared<IMUMsg>());
}

示例 3:const_cast — 与遗留 C API 交互

旧的激光雷达 SDK 可能没有 const 修饰,导致你传入的常量数据被拒绝。

#include <iostream>
using namespace std;// 模拟旧 C API
void lidar_process(char* buf) { cout << "Processing: " << buf << endl; }int main() {const char* frame = "LidarFrame";// 去掉 const 修饰以适配 API(底层不修改才安全)lidar_process(const_cast<char*>(frame));
}

示例 4:reinterpret_cast — 解析点云二进制数据

接收到的点云是网络字节流,需要直接 reinterpret 成结构体。

#include <iostream>
#include <cstdint>
using namespace std;#pragma pack(push, 1)
struct PointXYZ { float x, y, z; };
#pragma pack(pop)int main() {uint8_t buffer[sizeof(PointXYZ)] = {0x00,0x00,0x20,0x41, 0x00,0x00,0x48,0x42, 0x00,0x00,0x70,0x41};PointXYZ* pt = reinterpret_cast<PointXYZ*>(buffer);cout << "Point: " << pt->x << ", " << pt->y << ", " << pt->z << endl;
}

示例 5:组合使用 static_cast + const_cast

在类层次结构中,既要做类型转换,又要去掉 const。

#include <iostream>
using namespace std;struct Base { virtual ~Base() = default; };
struct Derived : Base { void work() { cout << "Derived work\n"; } };void process(const Base* b) {// 去掉 const 后向下转型auto d = static_cast<Derived*>(const_cast<Base*>(b));d->work();
}int main() {Derived obj;process(&obj);
}

示例 6:reinterpret_cast 用于硬件寄存器映射

嵌入式 SLAM(机器人)中访问传感器寄存器。

#include <iostream>
#include <cstdint>
using namespace std;volatile uint32_t fake_register = 0xAABBCCDD;int main() {volatile uint8_t* reg8 = reinterpret_cast<volatile uint8_t*>(&fake_register);cout << hex << "Low byte: 0x" << static_cast<int>(reg8[0]) << endl;
}

http://www.dtcms.com/a/327612.html

相关文章:

  • 使用pyqt5实现可勾选的测试用例界面
  • B站 韩顺平 笔记 (Day 16)
  • 如何以开发者的身份开发出比python更好的应用软件?
  • 攻击者将Linux摄像头武器化为攻击工具,可注入击键并发动攻击
  • 使用reqwest+select实现简单网页爬虫
  • 《Fast Automatic White Balancing Method by Color Histogram Stretching》论文笔记
  • 小米宠物空气净化器好用吗?希喂/小米/范罗士核心性能深度对比
  • 5G专网项目外场常见业务测试指南(六)-PingInfoView
  • 力扣面试150(54/150)
  • 如何构建PHP表单页面及验证相关原理(PHP基础)
  • 六十、【Linux系统lvs应用】LVS简介 、 LVS-NAT集群 、 LVS-DR集群
  • 微服务ETCD服务注册和发现
  • 3 Abp 核心框架(Core Framework)
  • 过程设计工具深度解析-软件工程之详细设计(补充篇)
  • 数字孪生如何推动智慧园区精细化管理
  • CV 医学影像分类、分割、目标检测,之【皮肤病分类】项目拆解
  • OHEM (在线难例挖掘) 详细讲解
  • 【Vue.js】生产设备规划工具(报价单Word文档生成)【开发全流程】
  • 无人机航拍数据集|第14期 无人机水体污染目标检测YOLO数据集3000张yolov11/yolov8/yolov5可训练
  • etcd 备份与恢复
  • Etcd客户端工具Etcd Workbench更新了1.2.0版本!多语言支持了中文,新增了许多快捷功能使用体验再次提升
  • Spark 运行流程核心组件(一)作业提交
  • 干货分享|如何从0到1掌握R语言数据分析
  • 小红书笔记信息获取_实在智能RPA源码解读
  • 邦纳BANNER相机视觉加镜头PresencePLUSP4 RICOH FL-CC2514-2M工业相机
  • C++实现LINGO模型处理程序
  • Java结课案例-景点人数统计的几种场景
  • 日期格式化成英文月,必須指定語言環境
  • Secure CRT做代理转发
  • HTTP应用层协议-长连接