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 时,我们就利用多态本身,为基类新增一个方法,用来获取类类型信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1619759.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Markdown中的LaTeX公式详解

引言 LaTeX是一种用于排版科学和数学文档的排版系统&#xff0c;它能够以高质量的方式生成复杂的数学公式。在CSDN&#xff08;Cnblogs和CSDN&#xff09;这样的博客平台中&#xff0c;也支持使用LaTeX语法插入数学公式。本文将详细介绍在CSDN中使用LaTeX公式的方法和常用语法&…

IgA | 对抗病原菌,帮助共生菌定植的“重要开关”

导 语&#xff1a;关于抗体&#xff0c;免疫和微生物 肠道微生物群的组成因个体而异&#xff0c;肠道微生物群中的特定细菌类群可能是某些肠内外疾病的独特有效驱动因素。对人类而言&#xff0c;精准且优先识别影响疾病易感性和严重性的细菌仍然是一项重大挑战。 很多时候我们想…

医院信息系统服务器存储维护,首都医科大学宣武医院电子病历系统服务器及存储设备维护服务项目招标公告...

产品介绍  飞顿lovely AFT是一台功能全面的皮肤美容工作站&#xff0c;它应用了光子领域最前沿的技术和科学成果&#xff0c;将一个工作平台与四个光子设备对接&#xff0c;组成一个功能十分强大的光子工作站。它可独立解决皮肤美容的各种问题&#xff0c;是目前应用最广泛&a…

合成生物学公司如何操纵微生物组

来源&#xff1a;肠道产业 这是《肠道产业》第 807 篇文章 编者按 近年来&#xff0c;合成生物学领域的研究不断推进&#xff0c;许多公司纷纷出手&#xff0c;将合成生物学用于治疗各种各样的疾病&#xff0c;包括靶向微生物组。那么有哪些在微生物组领域探索的合成生物学公司…

相机下载_美颜轻相机最新版下载-美颜轻相机app下载v1.70206 安卓版

美颜轻相机app是一款超棒的美颜相机工具。专业的实时相机&#xff0c;大量的各种滤镜挑选&#xff0c;丰富智能的功能拍照&#xff0c;完美的拍出你喜欢的效果&#xff01;还能自由补光&#xff0c;延迟拍照等等&#xff0c;功能强大&#xff01; 美颜轻相机最新版介绍 【魅力彩…

体内湿气重怎样祛除

1.如何判断自己身体是否有湿&#xff1f; 1.头发爱出油 2.面部油亮 3.睡觉留口水 &#xff08;湿气饱和自行流出&#xff09; 4.排便粘稠&#xff08;不易冲掉&#xff09;且多便。 5.小肚子大 6.耳内湿&#xff08;耳禅湿&#xff09;7.阴部潮湿。 湿是如何形成的&#xff1…

springboot整合rabbitmq死信队列

springboot整合rabbitmq死信队列 什么是死信 说道死信&#xff0c;可能大部分观众大姥爷会有懵逼的想法&#xff0c;什么是死信&#xff1f;死信队列&#xff0c;俗称DLX&#xff0c;翻译过来的名称为Dead Letter Exchange 死信交换机。当消息限定时间内未被消费&#xff0c;…

Linux网络编程经典书籍推荐

Linux网络编程经典书籍推荐 目录(?)[] 首先要说讲述TCP/IP的书很多&#xff0c;其中有3泰书很全。 分别是《TCP/IP详解》三卷本&#xff0c;《用TCP/IP进行网际互连》三卷本&#xff0c;《TCP/IP指南》《IPv6》四卷本 其中TCP/IP详解的作者还写了另外2本经典著作&#xff0c;《…

网络编程学习之经典书籍推荐

网络编程学习之经典书籍推荐 TCP/IP协议卷一、二、三下载地址 程序编号&#xff1a;510 程序名称&#xff1a; 《TCP/IP详解&#xff0c;卷1&#xff1a;协议》书 pdf格式 程序类型&#xff1a;电子书 文件大小&#xff1a; 13000 K 字节 上传时间&#xff1a;2003-3-18 18:07…

聚类分析 | MATLAB实现基于FCM模糊C均值聚类结果可视化

聚类分析 | MATLAB实现基于FCM模糊C均值聚类结果可视化 目录 聚类分析 | MATLAB实现基于FCM模糊C均值聚类结果可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 FCM模糊C均值聚类&#xff0c;聚类结果可视化&#xff0c;MATLAB程序。 FCM&#xff08;Fuzzy C-Means&a…

基于适应度相关算法优化的BP神经网络(预测应用) - 附代码

基于适应度相关算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于适应度相关算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.适应度相关优化BP神经网络2.1 BP神经网络参数设置2.2 适应度相关算法应用 4.测试结果&…

渗透测试工具ZAP入门教程(3)-扫描流程

使用ZAP扫描网站流程如下&#xff1a; 1&#xff09;、输入URL&#xff0c;点击启动浏览器&#xff0c;在打开的浏览器登录要扫描的网站&#xff0c;操作页面各种功能&#xff0c;尽可能遍历所有功能及页面 2&#xff09;、点击Spider Start按钮&#xff0c;爬取静态地址&…

HandlerMethod类源码解析

HandlerMethod类用于封装控制器方法信息&#xff0c;包含类信息、方法Method对象、参数、注解等信息&#xff0c;具体的接口请求是可以根据封装的信息调用具体的方法来执行业务逻辑&#xff1b; HandlerMethod有三个子类分别是InvocableHandlerMethod、ServletInvocableHandler…

Spring MVC 学习总结

学习目标 了解 Spring MVC 是什么&#xff0c;为什么要使用它或者说它能解决什么问题&#xff0c;其与 Spring 是什么关系。理解为什么配置 Spring MVC 的前端控制器的映射路径为 “/” 会导致静态资源访问不了&#xff0c;掌握怎么处理这个问题。掌握基于注解方式使用 Spring…

java反射之Method的invoke方法实现

在框架中经常会会用到method.invoke()方法&#xff0c;用来执行某个的对象的目标方法。以前写代码用到反射时&#xff0c;总是获取先获取Method&#xff0c;然后传入对应的Class实例对象执行方法。然而前段时间研究invoke方法时&#xff0c;发现invoke方法居然包含多态的特性&a…

java method方法_java入门(六) | 方法(Method)的定义和使用

上一期是对java的分支结构进行讲解和实练,分支结构有if 、if(判断语句..){满足条件的代码...}else{不满足的代码}、else if以及switch case,你对他们有理解的怎样呢? 这一期是对方法method的介绍,它也被称之为函数,它的基本格式为: 方法的修饰符 方法的返回值 方法的名字…

Java中的方法(method)

1.方法概述 什么是方法&#xff1f; 方法是具有独立功能的代码块组织成为一个整体&#xff0c;使其具有特殊功能的代码集 注意&#xff1a; 方法必须先创建才可以使用&#xff0c;该过程称为方法定义 方法创建后并不是直接运行的&#xff0c;需要手动使用后执行&#xff0c;该过…

计算机组成原理(主存储器的基本组成、 运算器的基本组成、 控制器的基本组成、完成一条指令的三个阶段)

主存储器的基本组成&#xff1a; 这个是读数据操作图&#xff1a; 读入数据与菜鸟驿站的取货流程差不多&#xff1a; 写入数据的过程与读入数据类似&#xff1a; 1、cpu 指明想要写入到那个位置&#xff08;写到MAR中&#xff09; 2、想要写入的数据会放到MDR中 3、c…

MVSNet 代码注释版 下载 (pytorch版)(注释非常详细,较源码结构有调整,使用起来更方便)

MVSNet 代码注释版 下载 &#xff08;注释非常详细&#xff0c;代码结构有所调整&#xff0c;使用起来更方便&#xff09; 本代码不仅进行了详细注释&#xff0c;还对源码做了相应调整&#xff0c;可以更方便用户使用&#xff0c; 结构上&#xff0c;更加清晰&#xff1b; 代…

超级计算机运行吃鸡,决赛圈的时候,如果两个人同时被手雷炸死该怎么办呢?...

这款这么火的绝地求生&#xff0c;在决赛圈的时候如果真的两个人被手雷同时炸死该怎么办呢&#xff1f;小编就告诉你自己的亲身经历吧。 第一个&#xff1a;手雷在你手中爆炸&#xff0c;然后与敌人同归&#xff0c;相信大多数人有这样一种习惯&#xff0c;捏住手雷5秒扔掉&…