dynamic_cast和static_cast和const_cast
dynamic_cast
在 C++ 中的作用
dynamic_cast
是 C++ 运行时类型转换(RTTI, Run-Time Type Identification)的一部分,主要用于:
- 安全的多态类型转换
- 检查类型的有效性
- 向下转换(Downcasting)
- 跨类层次的指针或引用转换
它只能用于 带有虚函数的类,否则 dynamic_cast
将无法工作。
1. dynamic_cast
的作用
1.1 向下转换(Downcasting)
用于将 基类(Base Class)指针/引用 转换为 派生类(Derived Class)指针/引用,并在运行时 检查类型安全性。
示例:
#include <iostream>
using namespace std;class Base {
public:virtual void show() { cout << "Base class\n"; } // 需要虚函数
};class Derived : public Base {
public:void show() override { cout << "Derived class\n"; }
};int main() {Base* basePtr = new Derived(); // 基类指针指向派生类对象// 使用 dynamic_cast 进行向下转换Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);if (derivedPtr) {derivedPtr->show(); // ✅ 成功转换并调用 Derived::show()} else {cout << "Conversion failed\n";}delete basePtr;return 0;
}
输出:
Derived class
✅ dynamic_cast
成功转换,因为 basePtr
实际指向的是 Derived
对象。
1.2 失败情况
如果 basePtr
实际上指向的是 Base
类型的对象,而不是 Derived
,那么转换会失败,返回 nullptr
(对于指针)。
Base* basePtr = new Base();
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);if (derivedPtr) {derivedPtr->show();
} else {cout << "Conversion failed\n"; // ✅ 这里转换失败
}
输出:
Conversion failed
2. dynamic_cast
适用于引用
dynamic_cast
也可以用于 引用转换,但如果转换失败,会抛出 std::bad_cast
异常。
#include <iostream>
#include <typeinfo>
using namespace std;class Base { public: virtual ~Base() {} };
class Derived : public Base {};int main() {Base baseObj;try {Derived& derivedRef = dynamic_cast<Derived&>(baseObj); // ❌ 失败,抛出异常} catch (const std::bad_cast& e) {cout << "Exception: " << e.what() << endl;}return 0;
}
输出:
Exception: std::bad_cast
✅ 由于 baseObj
不是 Derived
类型,dynamic_cast
失败并抛出 std::bad_cast
异常。
3. dynamic_cast
和 static_cast
的区别
比较项 | dynamic_cast | static_cast |
---|---|---|
转换类型 | 仅限于 带虚函数的多态类 | 任何相关类型 |
运行时检查 | ✅ 有类型检查(RTTI) | ❌ 无类型检查 |
失败情况 | 指针返回 nullptr ,引用抛出 std::bad_cast | 可能导致 未定义行为 |
转换方向 | 只能用于向下转换 | 向上、向下转换均可 |
性能 | 运行时开销较大(涉及 RTTI 查询) | 编译时转换,无额外开销 |
示例:static_cast
vs dynamic_cast
Base* basePtr = new Base();// static_cast(不会进行检查,可能导致未定义行为)
Derived* derivedPtr1 = static_cast<Derived*>(basePtr); // ❌ 可能出现未定义行为
derivedPtr1->show(); // 可能崩溃// dynamic_cast(安全,但可能返回 nullptr)
Derived* derivedPtr2 = dynamic_cast<Derived*>(basePtr); // ✅ 失败时返回 nullptr
if (derivedPtr2) derivedPtr2->show();
总结:
dynamic_cast
安全但慢,适合 不确定基类指针实际指向的对象类型 时。static_cast
快但危险,仅适合 明确知道转换是安全的情况下。
4. 什么时候使用 dynamic_cast
?
✅ 使用 dynamic_cast
的最佳场景
- 向下转换(基类指针/引用 → 派生类指针/引用)。
- 运行时类型检查(避免
static_cast
可能的未定义行为)。 - 接口类(如
Base* ptr
指向某个不确定类型的派生类,需要判断其类型)。
❌ 避免 dynamic_cast
的情况
- 不涉及多态(没有
virtual
函数,dynamic_cast
无法工作)。 - 已知类型安全的转换(可用
static_cast
代替)。 - 高性能场景(
dynamic_cast
有运行时开销)。
5. dynamic_cast
在实际应用中的示例
5.1 多态事件处理
class Event { public: virtual ~Event() {} };
class MouseEvent : public Event { public: void click() { cout << "Mouse clicked\n"; } };
class KeyboardEvent : public Event { public: void press() { cout << "Key pressed\n"; } };void handleEvent(Event* event) {if (MouseEvent* mouse = dynamic_cast<MouseEvent*>(event)) {mouse->click();} else if (KeyboardEvent* key = dynamic_cast<KeyboardEvent*>(event)) {key->press();} else {cout << "Unknown event\n";}
}int main() {MouseEvent mouse;KeyboardEvent keyboard;handleEvent(&mouse); // ✅ 输出 "Mouse clicked"handleEvent(&keyboard); // ✅ 输出 "Key pressed"return 0;
}
✅ dynamic_cast
允许在运行时确定事件的类型,并调用相应的处理逻辑。
const_cast
在 C++ 中的作用
const_cast
是 C++ 提供的 四种类型转换运算符(static_cast
、dynamic_cast
、const_cast
、reinterpret_cast
)之一,专门用于去掉或添加 const
/ volatile
限定符。
它允许:
- 移除
const
限定符(常见用途) - 移除
volatile
限定符 - 添加
const
(几乎没用)
1. const_cast
的基本用法
1.1 去掉 const
修饰符
通常,const_cast
用于将 const
指针转换为非 const
指针,从而允许修改 const
变量(⚠️ 仅适用于非常量对象)。
示例:
#include <iostream>
using namespace std;void modifyConstValue(const int* ptr) {int* modifiablePtr = const_cast<int*>(ptr); // 去掉 const 限定符*modifiablePtr = 42; // 现在可以修改它
}int main() {int x = 10;modifyConstValue(&x);cout << "x = " << x << endl; // ✅ 输出 x = 42return 0;
}
输出:
x = 42
✅ const_cast<int*>
移除了 ptr
的 const
限定符,使得 modifiablePtr
可以修改 x
。
2. const_cast
使用的注意事项
2.1 const_cast
不能修改真正的 const
变量
如果你试图修改一个 真正的 const
变量,行为是 未定义的(UB, Undefined Behavior)。
示例(错误):
const int y = 100;
int* ptr = const_cast<int*>(&y);
*ptr = 200; // ❌ 未定义行为
cout << "y = " << y << endl;
⚠️ 即使编译通过,运行结果可能是:
y = 100 // ❌ 修改失败(某些编译器可能优化 `y` 为常量)
或
y = 200 // ❌ 可能错误修改(取决于编译器)
为什么?
const int y = 100;
可能会被编译器优化到只读存储区,因此试图修改它可能导致 程序崩溃 或 无效修改。
✅ 正确的使用方式:
const_cast
只能用于去掉 const
修饰符的指针/引用,而不能用于真正的 const
变量。
3. const_cast
用于函数参数
3.1 const_cast
解除 const
限定
有时,我们在 只接受非 const
参数的旧 C 库 中,需要传递 const
变量,这时 const_cast
可以解决问题。
#include <iostream>
using namespace std;void legacyFunction(char* str) { // 旧 C 库接口,必须接收非 conststr[0] = 'H'; // 修改字符串
}void wrapperFunction(const char* str) {legacyFunction(const_cast<char*>(str)); // 去掉 const
}int main() {char text[] = "hello";wrapperFunction(text);cout << text << endl; // ✅ 输出 "Hello"return 0;
}
✅ const_cast<char*>
允许 legacyFunction()
修改字符串。
4. const_cast
用于成员函数
在 C++ 类中,const_cast
可用于 在 const
成员函数中修改成员变量。
4.1 修改 mutable
变量
如果某个成员变量在 const
方法中需要修改,推荐使用 mutable
,而不是 const_cast
。
class Example {
private:mutable int counter = 0;
public:void increaseCounter() const {counter++; // ✅ 因为 counter 是 mutable,可以在 const 方法中修改}
};
✅ mutable
是更好的选择!
4.2 const_cast
在 const
方法中修改成员变量
如果不能使用 mutable
,可以用 const_cast
强行去掉 const
。
class Example {
private:int counter = 0;
public:void modify() const {const_cast<Example*>(this)->counter = 100; // 去掉 const 限定符}
};
⚠️ 注意:这会破坏 const
语义,最好避免!
5. const_cast
与其他类型转换的区别
转换方式 | 用途 |
---|---|
const_cast | 仅用于 去掉或添加 const /volatile |
static_cast | 编译时转换,用于普通类型转换 |
dynamic_cast | 运行时类型转换,用于 多态类 |
reinterpret_cast | 低级别强制转换,用于不同类型的二进制转换 |
6. 什么时候应该使用 const_cast
?
✅ 适用场景
- 调用旧 C 库时,避免
const
兼容性问题(如const char*
转char*
)。 - 在
const
成员函数中修改成员变量(但推荐mutable
)。 - 特定场景下移除
const
以提高灵活性(如优化某些代码)。
❌ 不推荐使用的情况
- 试图修改真正的
const
变量(未定义行为)。 - 滥用
const_cast
破坏const
语义(影响代码可读性)。 - 可以使用
mutable
代替的情况。
7. const_cast
适用的真实案例
案例:日志系统
在 log()
方法中,可能希望在 const
对象中增加日志计数:
class Logger {
private:mutable int log_count = 0;
public:void log(const string& msg) const {cout << "Log: " << msg << endl;const_cast<Logger*>(this)->log_count++; // ✅ 修改 log_count}
};
✅ 这里使用 mutable
更合适,但 const_cast
也是可选方案。
8. 总结
const_cast
的作用
- ✅ 去掉
const
限定符,使const
指针/引用可以修改数据。 - ✅ 允许
const
方法修改成员变量(但推荐mutable
)。 - ✅ 用于传递
const
数据给不兼容const
的旧 C 代码。
⚠️ const_cast
的注意事项
- ❌ 不能修改真正的
const
变量,否则是 未定义行为(UB)。 - ❌ 滥用会破坏
const
语义,影响代码可读性。 - ❌ 如果可能,使用
mutable
代替const_cast
。
🚀 最佳实践:
- 如果可能,避免
const_cast
,使用mutable
或者static_cast
。 - 只有在调用 C 代码或
const
兼容性问题时使用const_cast
。 - 确保
const_cast
仅用于非const
变量,否则可能导致UB
(未定义行为)。
何时使用?
- ✅ 需要 安全的向下转换(从
Base*
到Derived*
)。 - ✅ 处理 运行时不确定的多态对象(如 GUI 事件、游戏对象)。
- ❌ 已知类型的转换 应该使用
static_cast
以提高性能。
结论
dynamic_cast
适用于多态类型转换,尤其是 向下转换。- 运行时类型检查(RTTI)确保转换安全,但性能较
static_cast
略低。 - 适用于事件处理、插件系统等场景,但不建议在高性能代码中滥用。
相关文章:

dynamic_cast和static_cast和const_cast
dynamic_cast 在 C 中的作用 dynamic_cast 是 C 运行时类型转换(RTTI, Run-Time Type Identification)的一部分,主要用于: 安全的多态类型转换检查类型的有效性向下转换(Downcasting)跨类层次的指针或引用…...

DEEPSEEK与GPT等AI技术在机床数据采集与数字化转型中的应用与影响
随着人工智能(AI)技术的迅猛发展,深度学习、自然语言处理等先进技术开始广泛应用于各行各业。在制造业尤其是机床行业,AI技术的融合带来了巨大的变革,尤其在机床数据采集与机床数字化方面的应用。本文将探讨DEEPSEEK、…...

高速存储文章目录
《zynq tcp万兆网和ftp协议分析-CSDN博客》 《国产fpga nvme ip高速存储方案设计_fpga 高速存储-CSDN博客》 《国微pcie switch 8748高速存储方案设计_国产pcie switch-CSDN博客》 《FPGA SATA高速存储设计-CSDN博客》 《FPGA NVME高速存储设计_690t fpga-CSDN博客》 《zy…...

车载测试工具 --- CANoe VH6501 进行Not Acknowledge (NAck) 测试
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…...

【清晰教程】通过Docker为本地DeepSeek-r1部署WebUI界面
【清晰教程】本地部署DeepSeek-r1模型-CSDN博客 目录 安装Docker 配置&检查 Open WebUI 部署Open WebUI 安装Docker 完成本地DeepSeek-r1的部署后【清晰教程】本地部署DeepSeek-r1模型-CSDN博客,通过Docker为本地DeepSeek-r1部署WebUI界面。 访问Docker官…...

Linux运维——用户管理
Linux用户管理 一、Linux用户管理要点二、常用命令2.1、groupadd2.2、groupdel2.3、groupmod2.4、groups2.5、useradd2.6、userdel2.7、passwd2.9、su2.10、sudo2.10.1、给普通用户授权 sudo2.10.2、 免密码授权 sudo 一、Linux用户管理要点 创建用户组 - 使用 groupadd删除用…...

mac下dify+deepseek部署,实现私人知识库
目前deepseek 十分火爆,本地部署实现私有知识库,帮助自己日常工作,上一篇使用工具cherry studio可以做到私人知识库。今天学习了一下,使用Dify链接deepseek,实现私人知识库,也非常不错,这里分享…...

Linux中设置开机运行指令
系统:Debian 12 使用systemd来设置开机自启动脚本或命令是一个更加现代且推荐的方法。下面是具体的步骤: 创建守护脚本 首先,你需要创建一个Shell脚本文件,比如mydaemon.sh,并在其中编写你的守护脚本逻辑。确保这个脚…...

IDEA中列举的是否是SpringBoot的依赖项的全部?在哪里能查到所有依赖项,如何开发自己的依赖项让别人使用
在 IntelliJ IDEA 中列举的依赖项并不一定是 Spring Boot 项目的全部依赖项。IDEA 通常只显示你在 pom.xml(Maven)或 build.gradle(Gradle)中显式声明的依赖项,而这些依赖项本身可能还会引入其他传递性依赖。 1. 如何…...

Ollama命令使用指南
Ollama 命令使用指南 Ollama 命令使用指南1. Ollama 命令概览2. Ollama 命令详解2.1 启动 Ollama2.2 创建模型2.3 查看模型信息2.4 运行模型2.5 停止运行的模型2.6 从注册表拉取模型2.7 推送模型到注册表2.8 列出本地模型2.9 查看正在运行的模型2.10 复制模型2.11 删除模型 3. …...

LIMO:上海交大的工作 “少即是多” LLM 推理
25年2月来自上海交大、SII 和 GAIR 的论文“LIMO: Less is More for Reasoning”。 一个挑战是在大语言模型(LLM)中的复杂推理。虽然传统观点认为复杂的推理任务需要大量的训练数据(通常超过 100,000 个示例),但本文展…...

Android studio怎么创建assets目录
在Android Studio中创建assets文件夹是一个简单的步骤,通常用于存储不需要编译的资源文件,如文本文件、图片、音频等 main文件夹,邮件new->folder-assets folder...

常见的前端框架和库有哪些
1. React 描述:由 Facebook 开发的一个 JavaScript 库,用于构建用户界面,尤其是单页面应用(SPA)。特点: 基于组件的架构,便于重用 UI 组件。使用虚拟 DOM 提升性能。容易与其他库和框架集成。 …...

【批量获取图片信息】批量获取图片尺寸、海拔、分辨率、GPS经纬度、面积、位深度、等图片属性里的详细信息,提取出来后导出表格,基于WPF的详细解决方案
摄影工作室通常会有大量的图片素材,在进行图片整理和分类时,需要知道每张图片的尺寸、分辨率、GPS 经纬度(如果拍摄时记录了)等信息,以便更好地管理图片资源,比如根据图片尺寸和分辨率决定哪些图片适合用于…...

数据结构与算法(test3)
七、查找 1. 看图填空 查找表是由同一类型的数据元素(或记录)构成的集合。例如上图就是一个查找表。 期中(1)是______________. (2)是______________(3)是_____关键字_______。 2. 查找(Searching) 就是根据给定的某个值, 在查…...

基于Python的人工智能驱动基因组变异算法:设计与应用(下)
3.3.2 数据清洗与预处理 在基因组变异分析中,原始数据往往包含各种噪声和不完整信息,数据清洗与预处理是确保分析结果准确性和可靠性的关键步骤。通过 Python 的相关库和工具,可以有效地去除噪声、填补缺失值、标准化数据等,为后续的分析提供高质量的数据基础。 在基因组…...

C++ 顺序表
顺序表的操作有以下: 1 顺序表的元素插入 给定一个索引和元素,这个位置往后的元素位置都要往后移动一次,元素插入的步骤有以下几步 (1)判断插入的位置是否合法,如果不合法则抛出异常 (2&…...

Mac(m1)本地部署deepseek-R1模型
1. 下载安装ollama 直接下载软件,下载完成之后,安装即可,安装完成之后,命令行中可出现ollama命令 2. 在ollama官网查看需要下载的模型下载命令 1. 在官网查看deepseek对应的模型 2. 选择使用电脑配置的模型 3. copy 对应模型的安…...

Docker 部署 redis | 国内阿里镜像
一、简易单机版 1、镜像拉取 # docker hub 镜像 docker pull redis:7.0.4-bullseye # 阿里云镜像 docker pull alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/redis_optimized:20240221-6.2.7-2.3.0 2、运行镜像 docker run -itd --name redis \n …...

48V电气架构全面科普和解析:下一代智能电动汽车核心驱动
48V电气架构:下一代智能电动汽车核心驱动 随着全球汽车产业迈入电动化、智能化的新时代,传统12V电气系统逐渐暴露出其无法满足现代高功率需求的不足。在此背景下,48V电气架构应运而生,成为现代电动汽车(EV)…...

滤波器截止频率的计算
1、RC低通滤波器 图1.1 RC低通滤波器 RC低通滤波器如图1.1所示,电阻R串联电容C,输入电压记为Ui ,输出电压记为Uo。 电容容抗记为,其中ω 2πf。 根据串联分压,列出传递函数。 将①式最右侧的分子与分母各乘以1-jω…...

服务器绑定 127.0.0.1 和 0.0.0.0 的区别
前言 IP 地址实际上并不是分配给计算机的,而是分配给网卡的,因此当计算机上存在多块网卡时,每一块网卡都会有自己的 IP 地址。 绑定 127.0.0.1 是绑定到 lookback 这个虚拟的本地回环接口,该接口只处理本机上的数据,…...

DeepSeek提示词手册
一、核心原则:基于DeepSeek的推理特性 自然语言优先undefinedDeepSeek擅长理解自然表达,无需复杂模板。例如: ❌旧模板:"你是专业分析师,需分三步回答,第一步…" ✅高效提问:"…...

校园网规划方案
个人博客站—运维鹿: http://www.kervin24.top CSDN博客—做个超努力的小奚: https://blog.csdn.net/qq_52914969?typeblog 本课程设计参考学习计算机网络 思科Cisco Packet Tracer仿真实验_哔哩哔哩_bilibili, 文章和pkg详见个人博客站: http://www.kervin24.to…...

python怎么求 一个数是否包含3
python求一个数包含3的方法: 1、使用“for i in 列表名”循环遍历列表中的每一个元素并将每个元素用str()函数转换成字符串格式 2、用“if str(3) in i”判断该元素中是否含有3 完整代码如下: 执行结果如下:...

ARM RFEIA指令作用
FreeRTOS第一个任务如何run起来的 在给ARM cortex R5适配FreeRTOS的过程中,在执行第一个task时,都是使用vTaskStartScheduler()函数,把第一个task运行起来的,其中比较关键在port.c实现的xPortStartScheduler()函数中,…...

【Kubernetes】常用命令全解析:从入门到实战(上)
🐇明明跟你说过:个人主页 🏅个人专栏:《Kubernetes航线图:从船长到K8s掌舵者》 🏅 🔖行路有良友,便是天堂🔖 目录 一、引言 1、Kubernetes简介 2、安装Kubernetes …...

项目实战(11)-双通道气体压力计V1.0
一. 产品简介: 1、项目背景是在实际应用中需要监控通道内气体的压力,压力计分为两个通道;通道一时实时监控;通道二是保压,设定保压值得上下限后通道内得气体压力值会一直保持在这个范围内。 二. 应用场景:…...

Node.js怎么调用到打包的python文件呢
在 Node.js 中调用打包后的 Python 可执行文件(如 PyInstaller 生成的 .exe 或二进制文件),可以通过以下步骤实现: 一、Python 打包准备 假设已有打包好的 Python 文件 your_script.exe(以 Windows 为例)&…...

Transformer 详解:了解 GPT、BERT 和 T5 背后的模型
目录 什么是 Transformer? Transformer如何工作? Transformer 为何有用? 常见问题解答:机器学习中的 Transformer 在技术领域,突破通常来自于修复损坏的东西。制造第一架飞机的人研究过鸟类。莱特兄弟观察了秃鹫如何在气流中保持平衡,意识到稳定性比动力更重要。…...