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

C++ 强制类型转换

C++ 四大强制类型转换

转换类型使用范围访问权限继承关系要求多态支持额外说明
static_cast适用于相关类型之间的转换,如基类<->派生类指针转换、数值类型转换等需满足访问权限(如基类继承方式)必须有继承关系,且访问权限允许可用于多态类型,但不做运行时检查编译时转换,效率高,但对非法转换不安全,向下转型可能导致未定义行为
dynamic_cast用于多态类型的安全向下转型或跨类层次指针转换需满足访问权限必须是多态类(含虚函数),有继承关系支持,执行运行时类型检查转换失败时,指针返回 nullptr,引用抛异常,性能开销较大
const_cast用于去除或添加 const / volatile 修饰无访问权限限制不依赖继承关系不涉及多态只能修改类型修饰符,不能改变类型本质,去除 const 后修改对象导致未定义行为
reinterpret_cast任意类型指针或整数间的转换,极其底层和不安全无访问权限限制不要求继承关系不支持不安全,直接按二进制重新解释,通常用于系统底层、硬件交互等特殊场景,慎用

static_cast

编译期类型检查,适合“已知关系”的转换

error C2440: “static_cast”: 无法从“B *”转换为“A *”, 需要存在寄存关系

class A {};
class B {};
int main()
{B b;A* a = static_cast<A*>(&b);
}

reinterpret_cast

完全底层强转,仅改变解释方式,不改地址内容
不能用于普通类型转换,例如:int → float (float、int底层内存解析不一样)

const_cast

去除 const,解除只读属性

dynamic_cast

支持多态转换,需有虚函数,需要RTTI(运行阶段类型识别)
dynamic_cast运算符将使用一个指向基类的指针来生成一个指向派生类的指针;否则,该运算符返回0(空指针);

典型实现步骤
当执行 dynamic_cast<DestType*>(srcPtr) 时,编译器生成的底层代码大致会做以下操作:

  • (1) 检查空指针
    如果 srcPtr 是 nullptr,直接返回 nullptr。
  • (2) 检查静态类型兼容性
    如果 DestType 和 srcPtr 的静态类型(编译时类型)无关(非继承关系),直接返回 nullptr。
  • (3) 查询 RTTI
    通过 srcPtr 对象的虚函数表(vtable)找到其 RTTI 信息(通常是 type_info 结构体),获取实际对象的动态类型。
  • (4) 遍历继承树
    向下转型(Downcast):检查 DestType 是否是实际对象的基类或派生类。如果是派生类,计算指针偏移量并调整。
    侧向转型(Crosscast):在多重继承中,可能需要调整指针指向目标类的子对象。
  • (5) 返回结果
    如果类型兼容,返回调整后的指针。否则,返回 nullptr。
class B1 {
public:virtual void f1() {}int b1_data;
};class B2 {
public:virtual void f2() {}int b2_data;
};class D : public B1, public B2 {
public:virtual void f1() override {} // 覆盖 B1::f1virtual void fd() {}          // D 的新虚函数int d_data;
};
int main()
{B2* d = new B2();B1* pb2 = dynamic_cast<B1*>(d);D* pb2s = static_cast<D*>(d);
}

pb2 不能转换成功,创建的B2类型不能转成B1类型
pb2s 能转换成功,但是运行的时候会产线未定义行为,因为分内存的时候只是分配了B2的内存大小,但是强制转成D,变成使用了D的内存大小,可能会访问非法内存

下图:
pb2s直接按编译向前减了8个字节(static_cast编译器的时候就进行转换了)
在这里插入图片描述

问题

为什么 static_cast 能正确处理多继承向上转型?

(1) 编译器已知继承关系
在编译时,编译器 完全知道 Derived 的继承结构(包括基类的顺序和偏移量)。
static_cast 直接根据继承关系计算指针调整,无需运行时信息。

(2) 指针调整是确定的
在多继承中,基类子对象的偏移量是编译期常量。例如:
Base1 的偏移量 = 0(首个子对象)。
Base2 的偏移量 = sizeof(Base1)。
static_cast 会根据目标基类类型,自动计算正确的偏移量。

(3) 不涉及运行时类型检查
static_cast 不依赖 RTTI(Run-Time Type Information),完全在编译期完成转换。
因此,即使没有虚函数(无虚表),static_cast 也能正确工作。

对比 dynamic_cast

dynamic_cast 也能向上转型,但它是为 向下转型(Downcasting) 设计的,向上转型时会退化为 static_cast:
dynamic_cast 的向上转型没有额外作用,反而可能误导代码读者(让人误以为需要运行时检查)。
static_cast 更清晰、更高效。

Base1* pb1 = dynamic_cast<Base1*>(&d); // 等价于 static_cast

为什么 static_cast 不能安全用于向下转型?

虽然 static_cast 能正确处理向上转型,但 向下转型(Downcasting) 时存在风险:
static_cast 不会检查 pb2 是否真的指向 Derived 对象,直接按继承关系调整指针,可能导致非法内存访问。此时必须用 dynamic_cast:

Base2* pb2 = new Base2;  // 纯 Base2 对象
Derived* pd = static_cast<Derived*>(pb2); // 危险!
http://www.lryc.cn/news/586855.html

相关文章:

  • 【读书笔记】《C++ Software Design》第六章深入剖析 Adapter、Observer 和 CRTP 模式
  • 开机自动启动同花顺,并设置进程优先级为高
  • Linux驱动开发1:设备驱动模块加载与卸载
  • 【Linux学习笔记】认识信号和信号的产生
  • JAVA JVM虚拟线程
  • HTML 初体验
  • 软件文档体系深度解析:工程视角下的文档架构与治理
  • OneCode3.0 VFS分布式文件管理API速查手册
  • jenkins使用Jenkinsfile部署springboot+docker项目
  • 代码随想录|图论|15并查集理论基础
  • Docker一键安装中间件(RocketMq、Nginx、MySql、Minio、Jenkins、Redis)脚步
  • SDN软件定义网络架构深度解析:分层模型与核心机制
  • Redis缓存设计与性能优化指南
  • 解码冯・诺依曼:操作系统是如何为进程 “铺路” 的?
  • [Nagios Core] CGI接口 | 状态数据管理.dat | 性能优化
  • 基于Redis Streams的实时消息处理实战经验分享
  • Appium源码深度解析:从驱动到架构
  • 使用macvlan实现容器的跨主机通信
  • 在Intel Mac的PyCharm中设置‘add bin folder to the path‘的解决方案
  • React强大且灵活hooks库——ahooks入门实践之常用场景hook
  • p4 大小写检查
  • Rust赋能文心大模型4.5智能开发
  • QCustomPlot绘图保存成PDF文件
  • 软考中级学习系列-- 阶码与尾数
  • 香港服务器Python自动化巡检脚本开发与邮件告警集成
  • 详解Linux下多进程与多线程通信(一)
  • Leetcode 3615. Longest Palindromic Path in Graph
  • OpenLoong技术观察 | 卓益得十年磨一剑:“行者”系列人形机器人技术演进观察
  • 构造函数延伸应用
  • DH(Denavit–Hartenberg)矩阵