【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)的线性时不…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
