【C++】类型转换 ④ ( 子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast )
文章目录
- 一、子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast
- 1、构造父类和子类
- 2、子类 和 父类 之间的类型转换 - 隐式类型转换
- 3、子类 和 父类 之间的类型转换 - 静态类型转换 static_cast
- 4、子类 和 父类 之间的类型转换 - 重新解释类型转换 reinterpret_cast
- 5、子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast
- 二、完整代码示例
- 1、代码示例
- 2、执行结果
在之前写过一篇 C++ 类型转换的博客 【C++ 语言】类型转换 ( 转换操作符 | const_cast | static_cast | dynamic_cast | reinterpret_cast | 字符串转换 ) , 简单介绍了 C++ 类型转换 ;
在 博客 【C++】类型转换 ① ( C 中的类型转换 | C++ 类型转换操作符 | const_cast | static_cast | dynamic_cast | reinterpret_cast ) 将 C 语言 和 C++ 中的类型转换进行了对比 ;
在 博客 【C++】类型转换 ② ( C++ 静态类型转换 static_cast | C 语言隐式转换弊端 | 代码示例 ) 中 , 主要分析了 静态类型转换 static_cast , 可以解决 C 语言隐式转换的弊端 ;
在博客 【C++】类型转换 ③ ( 重新解释类型转换 reinterpret_cast | 指针类型数据转换 ) 分析了 指针数据类型的转换 , 在 C 语言环境下 , 可以使用显示强制类型转换 , 在 C++ 环境中只能使用 重新解释类型转换 reinterpret_cast ;
本篇博客中 , 分析 C++ 环境下 使用 各种方式 进行 父类 和 子类 类型之间的转换 , 推荐使用 动态类型转换 dynamic_cast ;
一、子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast
C++ 面向对象 应用场景中 , 涉及到 父类 和 子类 之间的转换 ;
很明显 C 语言的 强制类型转换 , 不管是 隐式 还是 显示 转换 , 都无法转换 C++ 对象的类型 ;
动态类型转换 dynamic_cast 一般用于 父类 ( 对象 / 指针 / 引用 ) 和 子类 ( 对象 / 指针 / 引用 ) 之间的转换 , 是 C++ 语言特有的 , C 语言中没有该转换类型 ;
1、构造父类和子类
编写一个 父类 , 其中定义一个纯虚函数 ;
再编写两个 子类 , 重写 父类的 纯虚函数 , 每个子类再 各自定义一个 特有的函数 ;
// 父类
class Father
{
public:virtual void say() = 0;
};// 子类
class Son : public Father
{
public:void say(){cout << "Son" << endl;}// Son 子类的特有函数void son_say(){cout << "son_say" << endl;}
};// 子类2
class Son2 : public Father
{
public:void say(){cout << "Son2" << endl;}// Son2 子类的特有函数void son2_say(){cout << "son2_say" << endl;}
};
2、子类 和 父类 之间的类型转换 - 隐式类型转换
先创建 子类对象 ,
将子类对象的 地址赋值给 父类指针 , 其中包含了 隐式转换 ;
在下面的代码中 , 使用取地址符获取 Son 类型 子类对象的地址 , 指针类型是 Son* 类型 , 将该类型值 赋值给 Father* 指针 , 其中进行了 隐式类型转换 ;
Son son;// 创建父类指针 , 直接让父类指针指向子类对象// 不会报错 , 但是这么做有一定的风险Father* pFather = NULL;// 隐式类型转换pFather = &son;
此外 , 函数接收 父类指针形参 作为参数 , 如果调用该函数 , 传入子类指针 , 此时涉及到将 子类指针 Son* 隐式转为 父类指针 Father* ;
// 函数接收 父类对象 作为参数, 可传入子类对象
void objSay(Father* obj)
{
}// 调用函数, 传入子类对象指针
objSay(&son);
3、子类 和 父类 之间的类型转换 - 静态类型转换 static_cast
静态类型转换 static_cast , 可以在 C++ 编译器 编译时 对类型转换 进行检查 ;
如果 转换的类型不匹配 , 就会在编译时报错 , 避免出现更大的错误 ;
下面的代码中 , 使用取地址运算符 &son 获取 的 Son* 类型的 指针 , 将其使用 静态类型转换 static_cast 转为 Father* 类型的指针 ,
在 C++ 编译器编译阶段 , 会对类型进行检测 , 如果通过检测 , 则可以编译成功 , 如果类型错误 , 则会出现编译时报错的情况 ;
Son son;// 创建父类指针 , 直接让父类指针指向子类对象// 不会报错 , 但是这么做有一定的风险Father* pFather = NULL;// 静态类型转换 static_cast, 可以在编译时 对类型转换 进行检查pFather = static_cast<Father*>(&son);
下面的代码就是 执行静态类型转换 检查出错的情况 ,
Son 和 Son2 都是 Father 的子类 , 二者之间不能相互转化 , 只能是 父类 和 子类 之间进行相互转换 ;
类型转换错误报错 : error C2440: “static_cast”: 无法从“Son *”转换为“Son2 *” ;
Son son;Son2 son2;// 创建父类指针 , 直接让父类指针指向子类对象// 不会报错 , 但是这么做有一定的风险Father* pFather = NULL;// 静态类型转换 static_cast, 可以在编译时 对类型转换 进行检查pFather = static_cast<Father*>(&son);// 类型转换错误报错 : error C2440: “static_cast”: 无法从“Son *”转换为“Son2 *”// message : 与指向的类型无关;// 强制转换要求 reinterpret_cast、C 样式强制转换或函数样式强制转换Son2* pSon2 = static_cast<Son2*>(&son);
执行后 , 出现如下报错 :
已启动生成…
1>------ 已启动生成: 项目: HelloWorld, 配置: Debug Win32 ------
1>Test.cpp
1>D:\002_Project\006_Visual_Studio\HelloWorld\HelloWorld\Test.cpp(92,39): error C2440: “static_cast”: 无法从“Son *”转换为“Son2 *”
1>D:\002_Project\006_Visual_Studio\HelloWorld\HelloWorld\Test.cpp(92,16): message : 与指向的类型无关;强制转换要求 reinterpret_cast、C 样式强制转换或函数样式强制转换
1>已完成生成项目“HelloWorld.vcxproj”的操作 - 失败。
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
完整代码示例 :
#include "iostream"
using namespace std;// 父类
class Father
{
public:virtual void say() = 0;
};// 子类
class Son : public Father
{
public:void say(){cout << "Son" << endl;}// Son 子类的特有函数void son_say(){cout << "son_say" << endl;}
};// 子类2
class Son2 : public Father
{
public:void say(){cout << "Son2" << endl;}// Son2 子类的特有函数void son2_say(){cout << "son2_say" << endl;}
};// 函数接收 父类对象 作为参数, 可传入子类对象
void objSay(Father* obj)
{// 调用 父类 纯虚函数 可发生多态调用// 传入不同的子类 调用的是不同的函数obj->say();
}int main() {Son son;Son2 son2;// 创建父类指针 , 直接让父类指针指向子类对象// 不会报错 , 但是这么做有一定的风险Father* pFather = NULL;// 静态类型转换 static_cast, 可以在编译时 对类型转换 进行检查pFather = static_cast<Father*>(&son);// 类型转换错误报错 : error C2440: “static_cast”: 无法从“Son *”转换为“Son2 *”// message : 与指向的类型无关;// 强制转换要求 reinterpret_cast、C 样式强制转换或函数样式强制转换Son2* pSon2 = static_cast<Son2*>(&son);// 控制台暂停 , 按任意键继续向后执行system("pause");return 0;
};
执行结果 :
已启动生成…
1>------ 已启动生成: 项目: HelloWorld, 配置: Debug Win32 ------
1>Test.cpp
1>D:\002_Project\006_Visual_Studio\HelloWorld\HelloWorld\Test.cpp(92,39): error C2440: “static_cast”: 无法从“Son *”转换为“Son2 *”
1>D:\002_Project\006_Visual_Studio\HelloWorld\HelloWorld\Test.cpp(92,16): message : 与指向的类型无关;强制转换要求 reinterpret_cast、C 样式强制转换或函数样式强制转换
1>已完成生成项目“HelloWorld.vcxproj”的操作 - 失败。
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

4、子类 和 父类 之间的类型转换 - 重新解释类型转换 reinterpret_cast
C++ 中 父类 和 子类 之间类型转换 , 还可以使用 重新解释类型转换 reinterpret_cast ;
下面的代码中 , 将 Son* 指针类型 重新解释为 Father* 指针类型 ;
// C++ 强制类型转换 , 重新解释类型转换 reinterpret_castpFather = reinterpret_cast<Father*>(&son);pFather->say();
5、子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast
动态类型转换 dynamic_cast , 一般用于 子类 和 父类 之间的类型转换 ,
- 运行时 , 如果类型转换成功 , 则进行转换 ;
- 运行时 , 如果类型转换失败 , 则返回转换结果 NULL ;
借助上述特性 , 动态类型转换 dynamic_cast 可用于在 运行时 识别对象类型 ;
将 对象 强转为 指定类型对象, 如果失败了, 转换结果为 NULL , 说明被转换的对象 不是 指定类型的对象 ;
下面代码的作用是 : 将Father* obj 父类对象 强转为 Son* 子类对象 ,
- 如果转换成功, 说明 obj 对象就是 Son 子类对象 , 则执行 Son 子类对象特有的函数 ;
- 如果转换失败, 说明不是 Son 子类对象, 转换结果是 NULL , 也就是 0 , 后续不再处理 ;
// 将Father* obj 父类对象 强转为 Son* 子类对象// 如果转换成功, 说明 obj 对象就是 Son 子类对象// 如果转换失败, 说明不是 Son 子类对象, 转换结果是 NULL , 也就是 0Son* son = dynamic_cast<Son*>(obj);if (son != NULL){// 转换成功// 执行 Son 特有工作son->son_say();}
完整代码 , 参考下面章节的 完整代码示例 ;
二、完整代码示例
1、代码示例
#include "iostream"
using namespace std;// 父类
class Father
{
public:virtual void say() = 0;
};// 子类
class Son : public Father
{
public:void say(){cout << "Son" << endl;}// Son 子类的特有函数void son_say(){cout << "son_say" << endl;}
};// 子类2
class Son2 : public Father
{
public:void say(){cout << "Son2" << endl;}// Son2 子类的特有函数void son2_say(){cout << "son2_say" << endl;}
};// 函数接收 父类对象 作为参数, 可传入子类对象
void objSay(Father* obj)
{// 调用 父类 纯虚函数 可发生多态调用// 传入不同的子类 调用的是不同的函数obj->say();// 动态类型转换 dynamic_cast// 可用于在 运行时 识别对象类型// 将 对象 强转为 指定类型对象, 如果失败了, 转换结果为 NULL// 将Father* obj 父类对象 强转为 Son* 子类对象// 如果转换成功, 说明 obj 对象就是 Son 子类对象// 如果转换失败, 说明不是 Son 子类对象, 转换结果是 NULL , 也就是 0Son* son = dynamic_cast<Son*>(obj);if (son != NULL){// 转换成功// 执行 Son 特有工作son->son_say();}// 将Father* obj 父类对象 强转为 Son2* 子类对象// 如果转换成功, 说明 obj 对象就是 Son2 子类对象// 如果转换失败, 说明不是 Son2 子类对象, 转换结果是 NULL , 也就是 0Son2* son2 = dynamic_cast<Son2*>(obj);if (son2 != NULL){// 转换成功// 执行 Son2 特有工作son2->son2_say();}
}int main() {Son son;Son2 son2;// 创建父类指针 , 直接让父类指针指向子类对象// 不会报错 , 但是这么做有一定的风险Father* pFather = NULL;// 静态类型转换 static_cast, 可以在编译时 对类型转换 进行检查pFather = static_cast<Father*>(&son);// 类型转换错误报错 : error C2440: “static_cast”: 无法从“Son *”转换为“Son2 *”// message : 与指向的类型无关;// 强制转换要求 reinterpret_cast、C 样式强制转换或函数样式强制转换//Son2* pSon2 = static_cast<Son2*>(&son);// C++ 强制类型转换 , 重新解释类型转换 reinterpret_castpFather = reinterpret_cast<Father*>(&son);pFather->say();// 动态类型转换示例objSay(&son);objSay(&son2);// 控制台暂停 , 按任意键继续向后执行system("pause");return 0;
};
2、执行结果
执行结果 :
Son
Son
son_say
Son2
son2_say
Press any key to continue . . .

相关文章:
【C++】类型转换 ④ ( 子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast )
文章目录 一、子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast1、构造父类和子类2、子类 和 父类 之间的类型转换 - 隐式类型转换3、子类 和 父类 之间的类型转换 - 静态类型转换 static_cast4、子类 和 父类 之间的类型转换 - 重新解释类型转换 reinterpret_cast5、…...
在CentOS 7.9上搭建高性能的FastDFS+Nginx文件服务器集群并实现外部远程访问
文章目录 引言第一部分:FastDFS介绍与安装1.1 FastDFS简介1.2 FastDFS安装1.2.1 安装Tracker Server1.2.2 安装Storage Server 1.3 FastDFS配置1.3.1 配置Tracker Server1.3.2 配置Storage Server1.3.3 启动FastDFS服务 第二部分:Nginx配置2.1 Nginx安装…...
YOLOv8独家原创改进: AKConv(可改变核卷积),即插即用的卷积,效果秒杀DSConv | 2023年11月最新发表
💡💡💡本文全网首发独家改进:可改变核卷积(AKConv),赋予卷积核任意数量的参数和任意采样形状,为网络开销和性能之间的权衡提供更丰富的选择,解决具有固定样本形状和正方形的卷积核不能很好地适应不断变化的目标的问题点,效果秒殺DSConv 1)AKConv替代标准卷积进行…...
Docker pause/unpause命令
docker pause :暂停容器中所有的进程。 docker unpause :恢复容器中所有的进程。 语法 docker pause CONTAINER [CONTAINER...]docker unpause CONTAINER [CONTAINER...]实例 暂停数据库容器db01提供服务。 docker pause db01恢复数据库容器db01提供…...
PostgreSQL create or replace view和重建视图 有什么区别?
一、 replace vs 重建 遇到开发提了个问题,create or replace view和重建视图(dropcreate)有什么区别,查询资料整理了一下。 1. create or replace 当存在同名视图时,尝试将其替换新视图语句必须与现有视图查询具有相…...
Selenium 连接到现有的 Firefox 示例
当前环境: python 3.7 selenium 3.14.1 urllib3 1.26.8 Frefox 115.1.0esr(32位) geckodriver.exe 0.33.0 1 下载 Firefox 浏览器,根据自己的需要选择。 下载 Firefox 浏览器,这里有简体中文及其他 90 多种语言版本…...
小程序如何进行版本回退
当商家决定回退小程序版本时,可能是因为新版本出现了一些问题或者不符合预期,需要恢复到之前的稳定版本。下面具体介绍怎么回退小程序的版本。 在小程序管理员后台->版本设置处,点击版本回退。确认后,小程序会回退到上一次的版…...
15:00面试,15:06就出来了,问的问题有点变态。。。
从小厂出来,没想到在另一家公司又寄了。 到这家公司开始上班,加班是每天必不可少的,看在钱给的比较多的份上,就不太计较了。没想到8月一纸通知,所有人不准加班,加班费不仅没有了,薪资还要降40%…...
大数据-之LibrA数据库系统告警处理(ALM-37008 MPPDB服务不可用)
告警解释 告警模块每30秒周期性检测MPPDB服务健康状态,当检测到MPPDB健康状态为“故障”时产生告警。 当检测到MPPDB健康状态为“良好”时告警恢复。 告警属性 告警ID 告警级别 可自动清除 37008 致命 是 告警参数 参数名称 参数含义 ServiceName 产生…...
Pytorch-gpu环境篇
最最最头疼的就是配环境了 包之间的版本匹配问题 INSTALLING PREVIOUS VERSIONS OF PYTORCH 要考虑到pytorch和torchvision之间的匹配关系 显卡版本匹配问题...
互联网上门洗鞋店小程序
上门洗鞋店小程序门店版是基于原平台版进行增强的,结合洗鞋行业的线下实际运营经验和需求,专为洗鞋人和洗鞋店打造的高效、实用、有价值的管理软件系统。 它能够帮助洗鞋人建立自己的私域流量,实现会员用户管理,实现用户与商家的点…...
【深度学习笔记】04 概率论基础
04 概率论基础 概率论公理联合概率条件概率贝叶斯定理边际化独立性期望和方差模拟投掷骰子的概率随投掷次数增加的变化 概率论公理 概率(probability)可以被认为是将集合映射到真实值的函数。 在给定的样本空间 S \mathcal{S} S中,事件 A \m…...
45.113.200.1搜索引擎蜘蛛抓取不到网站内容页面可能的原因
以下是搜索引擎蜘蛛抓取不到网站内容页面的一些主要原因总结: 网站的 robots.txt 文件中禁止了搜索引擎蜘蛛访问网站某些页面或目录,导致搜索引擎无法抓取到相关页面的内容。 网站的页面存在重定向或者跳转,搜索引擎蜘蛛无法直接抓取到需要的…...
VMware 系列:vSphere Client安装配置常见问题及解决方案
vSphere Client安装配置常见问题及解决方案 1.本地通过远程桌面复制文件或者文件夹到windows服务器时出错提示“未指定的错误”问题描述:原因分析:解决方案:方法 1方法 2方法 32.远程桌面连接出现身份验证错误要求的函数不受支持问题描述:原因分析:解决方案:3.Windows se…...
FLASK博客系列5——模板之从天而降
我们啰啰嗦嗦讲了4篇,都是在调接口,啥时候能看到漂亮的页面呢?别急,今天我们就来实现。 来我们先来实现一个简单的页面。不多说,上代码。 app.route(/) def index():user {username: clannadhh}return <html>&…...
6.一维数组——用冒泡法将10个整数由大到小排序
文章目录 前言一、题目描述 二、题目分析 三、解题 程序运行代码 前言 本系列为一维数组编程题,点滴成长,一起逆袭。 一、题目描述 用冒泡法将10个整数由大到小排序 二、题目分析 三、解题 程序运行代码 #include<stdio.h> int main() {int …...
Wireshark的捕获过滤器
Wireshark的过滤器,顾名思义,作用是对数据包进行过滤处理。具体过滤器包括捕获过滤器和显示过滤器。本文对捕获过滤器进行分析。 捕获过滤器:当进行数据包捕获时,只有那些满足给定的包含/排除表达式的数据包会被捕获。 捕获过滤器…...
安陆FPGA调试中遇到的问题总结
参考链接:安陆FPGA踩坑填坑记录(梦里呓语回忆录)_fpga开发是个大坑-CSDN博客 上海安陆FPGA设置重上电启动速度_安路 fpga 加载时间-CSDN博客...
Springboot2+WebSocket
一、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dependency> 二、添加配置 新增配置文件 config/WebSocketConfig.java import org.springframewo…...
希尔伯特和包络变换
一、希尔伯特变换 Hilbert Transform,数学定义:在数学与信号处理的领域中,一个实值函数的希尔伯特变换是将信号x(t)与h(t)1/(πt)做卷积,以得到其希尔伯特变换。因此,希尔伯特变换结果可以理解为输入是x(t)的线性时不…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...
Python 高效图像帧提取与视频编码:实战指南
Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...
