c++ 判断基类指针指向的真实对象类型
在 c++ 面向对象使用中,我们常常会定义一个基类类型的指针,在运行过程中,这个指针可能指向一个基类类型的对象,也可能指向的是其子类类型的对象,那现在问题来了,我们如何去判断这个指针到底执行了一个什么类型的对象呢?
今天我们就聊一下这个问题,首先我们要区分是否允许 RTTI
,据此有不同办法。
1 允许使用 RTTI
在打开 rtti 的场景下,可以使用 dynamic_cast
和 typeid
这两个运算符来判断对象的真实类型。
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_cast
和 typeid
运算符来判断一个基类指针指向的具体对象类型;当禁用 RTTI
时,我们就利用多态本身,为基类新增一个方法,用来获取类类型信息。
相关文章:

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

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

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 四层模型 应用层:解决如何传输数据(依照什么格式/协议处理数据)的问题传输层:解决可靠性问题网络层:数据往哪里传,怎么找到目标主机数据链路层(物理层)&…...

基于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:存储可执行文件,主要包含客户端和服务端启动程序,如mysql.exe、mysqld.exe等 /docs:存放一些文档 /include:用于放置一些头文件,如:mysql.h、mysqld_error.h 等 …...

Mac操作系统Safari 17全新升级:秋季推出全部特性
苹果的内置浏览器可能是Mac上最常用的应用程序(是的,甚至比Finder、超级Mac Geeks还要多)。因此,苹果总是为其浏览器Safari添加有用的新功能。在今年秋天与macOS Sonoma一起推出的第17版中,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);- 参数:- sockfd : 通信的fd- buf : 要发送的数据- len : 发送数据的长度…...

ChatGPT提示与技巧分享:如何作出更好的提示2023年8月
对ChatGPT的一些酷炫技巧感兴趣吗?这里提供了一些可以帮助你充分利用ChatGPT,成为AI工具专家的技巧。 毫无疑问,ChatGPT是目前最广泛使用的人工智能工具之一。它不仅毫不留情地取代了一些特定领域常用的软件小工具(如智能对联、经典语录生…...

网络安全(自学黑客)一文全解
目录 特别声明:(文末附资料笔记工具) 一、前言 二、定义 三、分类 1.白帽黑客(White Hat Hacker) 2.黑帽黑客(Black Hat Hacker) 3.灰帽黑客(Gray Hat Hacker) 四…...

Vue中ElementUI结合transform使用时,发现弹框定位不准确问题
在近期开发中,需要将1920*1080放到更大像素大屏上演示,所以需要使用到transform来对页面进行缩放,但是此时发现弹框定位出错问题,无法准备定位到实际位置。 查看element-ui官方文档无果后,打算更换新的框架进行开发&am…...
(一)连续随机量的生成-基于分布函数
连续随机量的生成-基于分布函数 1. 概率积分变换方法(分布函数)2. Python编程实现指数分布的采样 1. 概率积分变换方法(分布函数) Consider drawing a random quantity X X X from a continuous probability distribution with …...

【springboot】Spring Cache缓存:
文章目录 一、导入Maven依赖:二、实现思路:三、代码开发: 一、导入Maven依赖: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId><…...
数学建模-建模算法(4)
python虽然不是完全为数学建模而生的,但是它完整的库让它越来越适合建模了。 - 线性规划:使用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…...
电子商务安全体系架构技术方面
技术方面是本文所要阐述的主要方面,因为它能够依靠企业自 身的努力来达到令人满意的安全保障效果。目前,关于电子商务安全体系的研究比 较多,有基于层次的体系,也有基于对象的体系,还有基于风险管理的体系࿰…...
新安装IDEA 常用插件、设置
新安装IDEA 常用插件、设置 mybatiscodeHelperProRestfulToolkit-fixJrebelmybatis log freepojo to jsonGrep ConsoleMaven HelperCamelCaseCamelCase常用设置 mybatiscodeHelperPro mapper.xml 编码校验 sql 生成,代码生成 RestfulToolkit-fix URI 跳转到对应的…...

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

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

Lazada商品详情接口 获取Lazada商品详情数据 Lazada商品价格接
一、引言 随着电子商务的迅速发展和普及,电商平台之间的竞争也日趋激烈。为了提供更好的用户体验和更高效的后端管理,Lazada作为东南亚最大的电商平台之一,开发了一种商品详情接口(Product Detail API)。该接口允许第…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...

Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...

第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...