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

c++ 判断基类指针指向的真实对象类型

在 c++ 面向对象使用中,我们常常会定义一个基类类型的指针,在运行过程中,这个指针可能指向一个基类类型的对象,也可能指向的是其子类类型的对象,那现在问题来了,我们如何去判断这个指针到底执行了一个什么类型的对象呢?
在这里插入图片描述

今天我们就聊一下这个问题,首先我们要区分是否允许 RTTI,据此有不同办法。

1 允许使用 RTTI

在打开 rtti 的场景下,可以使用 dynamic_casttypeid 这两个运算符来判断对象的真实类型。

1.1 使用 dynamic_cast

dynamic_cast 用于在运行时进行多态类型检查和转换,它可以将指向基类的指针转换为指向派生类的指针或引用。如果转换成功,则说明对象属于目标类或其派生类。如果转换失败,则返回空指针。
我们看如下例子,我们想判断指针 basePtr 是否指向了 Child2 类型的对象。总共进行了两次测试,第一次让该指针指向了 Child1 类型的对象,第二次则是指向了 Child2 类型的对象。

#include <iostream>class Basic {
public:virtual void say() {std::cout << "我是基类" << std::endl;}
};class Child1 : public Basic {
public:void say() {std::cout << "我是 child 1" << std::endl;}
};class Child2 : public Basic {
public:void say() {std::cout << "我是 child 2" << std::endl;}
};int main()
{Basic* basePtr;basePtr = new Child1();if (dynamic_cast<Child2*>(basePtr)) {std::cout << "[test 1]指针指向了 Child2 类型对象" << std::endl;} else {std::cout << "[test 1]指针没有指向 Child2 类型对象" << std::endl;}delete basePtr;basePtr = new Child2();if (dynamic_cast<Child2*>(basePtr)) {std::cout << "[test 2]指针指向了 Child2 类型对象" << std::endl;} else {std::cout << "[test 2]指针没有指向 Child2 类型对象" << std::endl;}delete basePtr;
}

让我们一起看看两次的打印,这是符合我们的预期的,使用 dynamic_cast 可以判断一个基类类型的指针是否指向了某个具体类类型。

在这里插入图片描述

在这里,有的朋友会好奇,我为什么添加了 say() 这么一个方法,凑数吗?确实是,就是凑数的dynamic_cast 是用于多态运行时的类型检查,如果我不增加这么一个方法,并且在基类中添加上 virtual 关键字,那就不存在多态,也就无从谈起运行时多态类型检查。下面是我将 virtual 去掉,或者干脆删除 say() 方法的编译结果。

在这里插入图片描述

1.2 使用 typeid

typeid 运算符返回一个 type_info 对象,该对象包含类型的相关信息。通过比较两个指针的类型信息,可以确定它们是否具有相同的类型。这里我们不用管 type_info 是什么东西,我们主要看看怎么用,下面继续看看刚刚的例子。

#include <iostream>class Basic {
public:virtual void say() {std::cout << "我是基类" << std::endl;}
};class Child1 : public Basic {
public:void say() {std::cout << "我是 child 1" << std::endl;}
};class Child2 : public Basic {
public:void say() {std::cout << "我是 child 2" << std::endl;}
};int main()
{Basic* basePtr;basePtr = new Child1();if (typeid(*basePtr) == typeid(Child2)) {std::cout << "[test 1]指针指向了 Child2 类型对象" << std::endl;} else {std::cout << "[test 1]指针没有指向 Child2 类型对象" << std::endl;}delete basePtr;basePtr = new Child2();if (typeid(*basePtr) == typeid(Child2)) {std::cout << "[test 2]指针指向了 Child2 类型对象" << std::endl;} else {std::cout << "[test 2]指针没有指向 Child2 类型对象" << std::endl;}delete basePtr;
}

运行结果,和刚刚使用 dynamic_cast 一样。我们这里是来判断基类指针是否指向了某个具体类对象,typeid 当然也可以用来判断两个指针指向的具体类类型是否相同,这里不再展开。

在这里插入图片描述
值得注意的是,使用 typeid 时,如果去掉基类方法中的 virtual 关键字,编译并不会报错,但运行结果肯定会错,此时因为不存在多态,该运算符始终会返回基类的信息。

2 不允许使用 RTTI

出于某些原因,你的项目可能禁用了 RTTI,那这个时候我们应该怎么判断基类指针指向的具体类呢?我们还能利用多态本身,就是给基类新增一个虚方法,子类在必要的时候来重写。

下面我们继续用刚刚的例子,一起看看代码吧。

#include <iostream>class Basic {
public:virtual void say() {std::cout << "我是基类" << std::endl;}virtual bool isChild2() {return false;}
};class Child1 : public Basic {
public:void say() {std::cout << "我是 child 1" << std::endl;}
};class Child2 : public Basic {
public:void say() {std::cout << "我是 child 2" << std::endl;}bool isChild2() {return true;}
};int main()
{Basic* basePtr;basePtr = new Child1();if (basePtr->isChild2()) {std::cout << "[test 1]指针指向了 Child2 类型对象" << std::endl;} else {std::cout << "[test 1]指针没有指向 Child2 类型对象" << std::endl;}delete basePtr;basePtr = new Child2();if (basePtr->isChild2()) {std::cout << "[test 2]指针指向了 Child2 类型对象" << std::endl;} else {std::cout << "[test 2]指针没有指向 Child2 类型对象" << std::endl;}delete basePtr;
}

我们新增了一个 isChild2() 的方法,用来判断该类是否是 Child2 类型,因为我这里只需要判断基类指针是否指向了 Child2 类型的对象,所以就直接增加了个 bool 返回值的接口进行判断了。在实际使用时,也可以返回枚举变量,分别对应例子中的三个类。

3 总结

当项目允许 RTTI 时,我们可以使用 dynamic_casttypeid 运算符来判断一个基类指针指向的具体对象类型;当禁用 RTTI 时,我们就利用多态本身,为基类新增一个方法,用来获取类类型信息。

相关文章:

c++ 判断基类指针指向的真实对象类型

在 c 面向对象使用中&#xff0c;我们常常会定义一个基类类型的指针&#xff0c;在运行过程中&#xff0c;这个指针可能指向一个基类类型的对象&#xff0c;也可能指向的是其子类类型的对象&#xff0c;那现在问题来了&#xff0c;我们如何去判断这个指针到底执行了一个什么类型…...

退出屏保前玩一把游戏吧!webBrowser中网页如何调用.NET方法

本文主要以 HackerScreenSaver 新功能的开发经历介绍 webBrowser中网页如何调用.NET方法的过程。 1. 背景 之前开源了一款名为 HackerScreenSaver 的 Windows 屏保程序。该程序具有模拟黑客炫酷界面的特点&#xff0c;用户可以将自定义的网页作为锁屏界面。不久前&#xff0c;…...

hive-列转行

转成 select customer_code,product_type from temp.temp_xx LATERAL VIEW explode(SPLIT(product_types,,)) table_tmp AS product_type where customer_code K100515182...

【网络】IP网络层和数据链路层

IP协议详解 1.概念 1.1 四层模型 应用层&#xff1a;解决如何传输数据&#xff08;依照什么格式/协议处理数据&#xff09;的问题传输层&#xff1a;解决可靠性问题网络层&#xff1a;数据往哪里传&#xff0c;怎么找到目标主机数据链路层&#xff08;物理层&#xff09;&…...

基于Spring Gateway路由判断器实现各种灰度发布场景

文章目录 1、灰度发布实现1.1 按随机用户的流量百分比实现灰度1.2 按人群划分实现的灰度1.2.1 通过Header信息实现灰度1.2.2 通过Query信息实现灰度1.2.3 通过RemoteAdd判断来源IP实现灰度 2、路由判断器2.1. After2.2. Before2.3. Between2.4. Cookie2.5. Header2.6. Host2.7.…...

mysql57、mysql80 目录结构 之 Windows

查看mysql 数据存储的位置 /bin&#xff1a;存储可执行文件&#xff0c;主要包含客户端和服务端启动程序&#xff0c;如mysql.exe、mysqld.exe等 /docs&#xff1a;存放一些文档 /include&#xff1a;用于放置一些头文件&#xff0c;如&#xff1a;mysql.h、mysqld_error.h 等 …...

Mac操作系统Safari 17全新升级:秋季推出全部特性

苹果的内置浏览器可能是Mac上最常用的应用程序&#xff08;是的&#xff0c;甚至比Finder、超级Mac Geeks还要多&#xff09;。因此&#xff0c;苹果总是为其浏览器Safari添加有用的新功能。在今年秋天与macOS Sonoma一起推出的第17版中&#xff0c;Safari可以帮助你提高工作效…...

UDP通信、本地套接字

#include <sys/types.h> #include <sys/socket > ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);- 参数&#xff1a;- sockfd : 通信的fd- buf : 要发送的数据- len : 发送数据的长度…...

ChatGPT提示与技巧分享:如何作出更好的提示2023年8月

​对ChatGPT的一些酷炫技巧感兴趣吗?这里提供了一些可以帮助你充分利用ChatGPT&#xff0c;成为AI工具专家的技巧。 毫无疑问&#xff0c;ChatGPT是目前最广泛使用的人工智能工具之一。它不仅毫不留情地取代了一些特定领域常用的软件小工具&#xff08;如智能对联、经典语录生…...

网络安全(自学黑客)一文全解

目录 特别声明&#xff1a;&#xff08;文末附资料笔记工具&#xff09; 一、前言 二、定义 三、分类 1.白帽黑客&#xff08;White Hat Hacker&#xff09; 2.黑帽黑客&#xff08;Black Hat Hacker&#xff09; 3.灰帽黑客&#xff08;Gray Hat Hacker&#xff09; 四…...

Vue中ElementUI结合transform使用时,发现弹框定位不准确问题

在近期开发中&#xff0c;需要将1920*1080放到更大像素大屏上演示&#xff0c;所以需要使用到transform来对页面进行缩放&#xff0c;但是此时发现弹框定位出错问题&#xff0c;无法准备定位到实际位置。 查看element-ui官方文档无果后&#xff0c;打算更换新的框架进行开发&am…...

(一)连续随机量的生成-基于分布函数

连续随机量的生成-基于分布函数 1. 概率积分变换方法&#xff08;分布函数&#xff09;2. Python编程实现指数分布的采样 1. 概率积分变换方法&#xff08;分布函数&#xff09; Consider drawing a random quantity X X X from a continuous probability distribution with …...

【springboot】Spring Cache缓存:

文章目录 一、导入Maven依赖&#xff1a;二、实现思路&#xff1a;三、代码开发&#xff1a; 一、导入Maven依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId><…...

数学建模-建模算法(4)

python虽然不是完全为数学建模而生的&#xff0c;但是它完整的库让它越来越适合建模了。 - 线性规划&#xff1a;使用scipy.optimize.linprog()函数 python from scipy.optimize import linprogc [-1, 4] A [[-3, 1], [1, 2]] b [6, 4] x0_bounds (None, None) x1_bound…...

python之函数返回数据框

1.原始文件 ##gff-version 3 Chr1A IWGSC_v2.1 gene 40098 70338 33 - . IDTraesCS1A03G0000200;previous_idTraesCS1A02G000100;primconfHC;NameTraesCS1A03G0000200;cdsCDS_OK;mappingfullMatchWithMissmatches Chr1A IWGSC_v2.1 mRN…...

电子商务安全体系架构技术方面

技术方面是本文所要阐述的主要方面&#xff0c;因为它能够依靠企业自 身的努力来达到令人满意的安全保障效果。目前&#xff0c;关于电子商务安全体系的研究比 较多&#xff0c;有基于层次的体系&#xff0c;也有基于对象的体系&#xff0c;还有基于风险管理的体系&#xff0…...

新安装IDEA 常用插件、设置

新安装IDEA 常用插件、设置 mybatiscodeHelperProRestfulToolkit-fixJrebelmybatis log freepojo to jsonGrep ConsoleMaven HelperCamelCaseCamelCase常用设置 mybatiscodeHelperPro mapper.xml 编码校验 sql 生成&#xff0c;代码生成 RestfulToolkit-fix URI 跳转到对应的…...

ChromeOS 的 Linux 操作系统和 Chrome 浏览器分离

导读科技媒体 Ars Technica 报道称&#xff0c;谷歌正在将 ChromeOS 的浏览器从操作系统中分离出来 —— 让它变得更像 Linux。虽然目前还没有任何官方消息&#xff0c;但这项变化可能会在本月的版本更新中推出。 据介绍&#xff0c;谷歌将该项目命名为 "Lacros"——…...

哔哩哔哩 B站 bilibili 视频倍速设置 视频倍速可自定义

目录 一、复制如下代码 二、在B站视频播放页面进入控制台 三、将复制的代码粘贴到下方输入框&#xff0c;并 回车Enter 即可 四、然后就可以了 一、复制如下代码 &#xff08;该代码用于设置倍速为3&#xff0c;最后的数值是多少就是多少倍速&#xff0c;可以带小数点&#…...

Lazada商品详情接口 获取Lazada商品详情数据 Lazada商品价格接

一、引言 随着电子商务的迅速发展和普及&#xff0c;电商平台之间的竞争也日趋激烈。为了提供更好的用户体验和更高效的后端管理&#xff0c;Lazada作为东南亚最大的电商平台之一&#xff0c;开发了一种商品详情接口&#xff08;Product Detail API&#xff09;。该接口允许第…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...