C++基础语法:RTTI(运行时识别)之一:dynamic_cast和typeid

news2024/9/20 6:19:16

前言
       

         "打牢基础,万事不愁" .C++的基础语法的学习."学以致用,边学边用",编程是实践性很强的技术,在运用中理解,总结.   

引入 

        RTTI是C++11加入的内容,可以应用在简单或复杂的场合下。简单理解RTTI的原理,尝试推导typeid的相关内容。以<C++ Prime Plus> 6th Edition(以下称“本书”)内容为参考。

RTTI的3个元素

        dynamic_cast:按翻译的字面意思---动态转换。派生类指针转化为基类指针

        typeid和type_info:指出类型及类型信息。

dynamic_cast的理解

        本书内容写得比较多,如果有多态的概念,应该很好理解什么是“动态转换”(dynamic_cast) 

        回顾多态

                基类引用可以指向派生类对象----多态的基本概念。或者说派生类对象可以转成基类引用

                同理:派生类指针可以转化成基类指针。基类指针调用虚方法时,实则调用派生类方法

        dynamic_cast的写法

                dynamic_cast<想转化成的指针类型>(被转化的指针) ;

                函数原型:dynamic_cast<Type *>(pt)

                当被转化的指针pt属于Type类型,或者从Type直接或间接派生而来,则运算符的返回值是一个Type类型的指针。即

                Type * tp=dynamic_cast<Type *>(pt)   //tp是Type类型指针,被用来接收运算后的返回值

                如果被转化指针pt不满足“属于Type类型,或者从Type直接或间接派生而来”这个条件,上面式子仍然成立,但结果为0(或nullptr)---空指针

        dynamic_cast的用法

                根据dynamic_cast 的定义,他的用法是比较固定的,大致如下:

//伪代码
Type* tp;
if(tp=dynamic_cast<Type*>(pt)){
    tp->fun();
}

                先判断能否转换,如果可以调用方法。否则转换后结果为0,也就不执行方法调用。

                此处代码与平时写的代码稍微有点区别,一般if里用的是比较表达式或者逻辑表达式,用赋值表达式(=)通常情况下是误用相等判断表达式(==),但这里确实是赋值表达式,因为转换不成功,tp的值是0,由此决定分支结构的走向。

====================内容分割线=============================================

以下内容属于推测 ,不可用

         dynamic_cast的函数定义

                尝试写出 dynamic_cast的函数定义

//伪代码
template<class Type>
Type* dynamic_cast(Type* t){
    if(t属于继承序列)
        return t;
    else
        return 0;
}

        问题是:在模板函数定义后,调用时如何使用类型指针。 

                       这里的Type需要包含自定义类型,内置数据类型,甚至模板类型(模板类也可以继承)

                        如何用表达式表达出一个类属于另一个类对象的直接和间接继承关系

====================内容分割线============================================ 

typeid的理解

        <C++ Prime Plus> 6th Edition(以下称“本书”)P646内容:

        typeid运算符使得能够确定两个对象是否为同种类型。它与sizeof有些相像,可以接受两种参数:类名和结果为对象的表达式。

        ----解读:红色部分说明了typeid的作用。如果只是使用typeid也够了。

        以下是typeid运算符的使用:

/*已测试*/
/*typeid运算符的使用*/
#include<iostream>
#include<typeinfo>
using namespace std;

class Demo{};									//声明class类

template<class T>								//声明泛型类
class DemoT{};

int main(void) {
	const type_info& ti = typeid(3);			//1参数使用值
	cout << "使用值得到的类型是:" << ti.name() << endl;
	double d = 0.5;
	const type_info& ti2 = typeid(d);			//2参数使用变量
	cout << "使用变量得到的类型是:" << ti2.name() << endl;
	const type_info& ti3 = typeid(string);		//3参数使用已标准化的类名
	cout << "使用标准类名string得到的类型是:" << ti3.name() << endl;
	const type_info& ti4 = typeid(Demo);		//4参数使用自定义class类
	cout << "使用自定义class类名Demo得到的类型是:" << ti4.name() << endl;
	const type_info& ti5 = typeid(DemoT<int>);	//5参数使用自定义模板类
	cout << "使用自定义模板类名DemoT<int>得到的类型是:" << ti5.name() << endl;
	const type_info& ti6 = typeid(DemoT<int>*);	//6参数使用指针
	cout << "使用自定义模板类名DemoT<int>的指针得到的类型是:" << ti6.name() << endl;
	const type_info& ti7 = typeid(Demo&);		//7参数使用引用,结果同4
	cout << "使用自定义class类名Demo引用得到的类型是:" << ti7.name() << endl;
}

结果: 

使用值得到的类型是:int
使用变量得到的类型是:double
使用标准类名string得到的类型是:class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
使用自定义class类名Demo得到的类型是:class Demo
使用自定义模板类名DemoT<int>得到的类型是:class DemoT<int>
使用自定义模板类名DemoT<int>的指针得到的类型是:class DemoT<int> *
使用自定义class类名Demo引用得到的类型是:class Demo

        说明:

         接收typeid返回值的数据类型必须是const type_info&,使用const type_info或 type_info&都将报错,以此可以推出typeid的返回类型是const,但为何不能用变量const type_info接收原因未知.

=========================内容分割线========================================

typeid的使用也是比较容易的,尝试还原出他的函数定义,加深一点思考

首先,type_info的类定义:

        思路:type_info调用name()函数得到了类名的字符串,还有重载了"=="和"!="运算符,所以尝试给出定义如下:

//尝试还原type_info定义,不一定准确
//要求string类也重载operator==()和operator!=(),字符串比较
class type_info{
    string name;
public:
    type_info(const string& na):name(na){}    //构造函数
    string name(){return name;}
    bool operator==(const type_info& ti){     //重载相等比较运算符
        return this.name()==ti.name();
    }
    bool operator!=(const type_info& ti){     //重载不等比较运算符
        return this.name()!=ti.name();
    }
}

 尝试typeid运算符的定义

        typeid可以接受类名和对象名

        C++没有反射机制(至少本书没看见),那么是怎样得到类名的呢。首先想到函数重载       

//伪代码
const type_info& typeid(int a){
    return type_info("int");
}

const type_info& typeid(double a){
    return type_info("double");
}

     起码对C++底层来说,内置数据类型和标准类型如string,可以识别.对于自定义class类和模板类,在他们编译的时候,将他们的信息注册到某个位置,并且加入类似代码.当然这样做肯定比较麻烦. 

        假设有一个类叫TypeName,它的对象是类名,可被typeid作为形参而使用。因此存在以下函数

       const  type_info& typeid(TypeName tn);                //函数原型

        要求TypeName能识别所有类型及其对象,函数定义大概是这个样子:

//伪代码
const  type_info& typeid(TypeName tn){
    if(tn被识别为int类型)
        return type_info("int");
    else if(tn被识别为double类型)
        return type_info("double");    
    ...                                //其他
}        

        这个TypeName类起的作用和java里的Object类相类似,是所有类(包括模板和内置数据类型)的父类.估计要有修改C++编译器的能力才能做到这一点,所以到此为止了

        .还有一个问题就是返回的引用被引用接收,照理说得不到正确结果,上面也提到过.C++语法应用:从return机制看返回指针,返回引用-CSDN博客

        也许有人会说,回溯一个已经定义好的程序,写了半天什么也没出个结果,不是浪费时间和精力吗?

        笔者的想法是:编程重在思考.回头再看:type_info和typeid到底干了什么?用一个全局函数typeid实现了信息的提取(放到了type_info类中),这不就是设计者的思路吗?就算自己写不出来,这种思路放到其他地方也是可以试一试的.

=========================内容分割线======================================= 

其他

        本书后面有个dynamic_cast和typeid用法比较的例子,typeid是显式指定类,用起来不如dynamic_cast,这个比较好理解,dynamic_cast支持多态,优先选用.

        typeid的使用也是比较固定的一行代码:

//伪代码
if(typeid(类型对象,变量,值或者类名)==typeid(类型对象,变量,值或者类名)){ //如果两个数据属于同一类型
    ......        //想做的事
}

小结 

        dynamic_cast和typeid的简单理解和应用.他们的典型使用都是放在一个if当中做判断.

        

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

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

相关文章

【error】The minimum required version for Powerlevel10k is 5.1

文章目录 一、背景二、原因三、解决1、安装 ZSH 最新版本2、效果3、下载了还是显示 ZSH 版本为 5.0.2 怎么办 一、背景 安装 ZSH 主题 Powerlevel10k 时报错&#xff1a; You are using ZSH version 5.0.2. The minimum required version for Powerlevel10k is 5.1. Type ‘ec…

ppt一键生成免费版软件有哪些?如何高效生成论文答辩?

答辩经验丰富的人都知道&#xff0c;制作论文答辩ppt是一项既繁琐又耗时的工作。 我们需要从数万字的论文中提炼关键点&#xff0c;梳理内容的逻辑关系&#xff0c;然后进行细致的排版和美化&#xff0c;最后还要进行反复的检查和试讲。整个过程不仅耗费时间&#xff0c;而且需…

MVP 最简可行产品

MVP&#xff08;最小可行产品&#xff09;是一种产品开发策略&#xff0c;其主要目的是用最少的时间和资源&#xff0c;开发一个包含最基本必要功能的产品。这样做的目的是能够以最小的成本进入市场&#xff0c;获取用户反馈&#xff0c;再根据反馈逐步优化产品。 MVP是什么 …

1网络安全的基本概念

文章目录 网络安全的基本概念可以总结为以下几个方面&#xff1a; 网络安全的需求&#xff1a; 信息安全的重要性&#xff1a;信息安全是计算机、通信、物理、数学等领域的交叉学科&#xff0c;对于社会的发展至关重要。信息安全的目标&#xff1a;主要包括保密性、完整性、可用…

C/S架构与B/S架构的适用场景分析

C/S架构&#xff08;客户端/服务器架构&#xff09;与B/S架构&#xff08;浏览器/服务器架构&#xff09;在适用场景上各有特点&#xff0c;主要取决于应用的具体需求、用户群体、系统维护成本、跨平台需求等因素。 一、C/S架构的适用场景 1、高性能与交互性要求高的应用&…

闯关leetcode——58. Length of Last Word

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/length-of-last-word/description/ 内容 Given a string s consisting of words and spaces, return the length of the last word in the string. A word is a maximal substring consisting of…

docker从容器提取镜像并上传至dockerhub

一、使用commit从容器中提取镜像 例如 //docker commit 容器名 想要创建的镜像名:版本号 docker commit epsilon_planner epsilon_planner:latest导出完成后镜像如图所示 二、登陆dockerhub并创建仓库 登陆dockerhub&#xff0c;点击Create repository创建仓库&#xff0c…

小程序体验版无法正常请求接口,开启 调试可以正常请求

在本地开发工具可以正常访问小程序&#xff0c;上传代码后打开体验版&#xff0c;界面无法请求接口&#xff0c;手机小程序打开调试模式可以正常访问。这可以查看下小程序后台是否设置了服务器域名以及业务域名 然后查看小程序开发工具 - 详情 - 项目配置 重新上传代码&#xf…

北斗盒子TD20——水上作业的安全防线,落水报警守护生命

在广阔的水域上&#xff0c;水上作业人员面临着多变的环境和潜在的风险。近年来&#xff0c;随着海洋经济的快速发展&#xff0c;海上作业活动日益频繁&#xff0c;人员安全问题也日益凸显。传统的海上救援手段存在诸多不足&#xff0c;如救援响应时间长、定位不准确等。 水上…

SpringBoot教程(三十) | SpringBoot集成Shiro(权限框架)

SpringBoot教程&#xff08;三十&#xff09; | SpringBoot集成Shiro&#xff08;权限框架&#xff09; 一、 什么是Shiro二、Shiro 组件核心组件其他组件 三、流程说明shiro的运行流程 四、SpringBoot 集成 Shiro1. 添加 Shiro 相关 maven2. 添加 其他 maven3. 设计数据库表4.…

JSONC:为JSON注入注释的力量

JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;广泛应用于Web开发、配置文件和数据存储等领域。 其简洁的语法和易于解析的特点&#xff0c;使得JSON成为了现代编程中不可或缺的一部分。然而&#xff0c;JSON的一个显著缺点是…

波分技术基础 -- MS-OTN介绍

什么是MS-OTN 由于OTN最小交叉颗粒度为ODU0&#xff0c;承载小颗粒业务时带宽利用率较低&#xff1b;且无法承载分组业务&#xff0c;随着MPLS-TP技术的成熟&#xff0c;MS-OTN时代来临。MS-OTN&#xff08;Multi-Service Optical Transport Network&#xff09;&#xff1a;核…

【论文解读系列】用于自监督点云表示的生成变分对比学习

Generative Variational-Contrastive Learning for Self-Supervised Point Cloud Representation | IEEE Transactions on Pattern Analysis and Machine Intelligence (acm.org) 作者&#xff1a;Bohua Wang; Zhiqiang Tian; Aixue Ye; Feng Wen; Shaoyi Du; Yue Gao 摘要 三…

VS code 查看 ${workspaceFolder} 目录指代路径

VS code 查看 ${workspaceFolder} 目录指代路径 引言正文 引言 在 VS code 创建与运行 task.json 文件 一文中我们已经介绍了如何创建属于自己的 .json 文件。在 VS code 中&#xff0c;有时候我们需要添加一些文件路径供我们导入自定义包使用&#xff0c;此时&#xff0c;我们…

Github Wiki 超链接 转 码云Gitee Wiki 超链接

Github Wiki 超链接 转 码云Gitee Wiki 超链接 Github 是 &#xff1a;[[相对路径]] Gitee 是 &#xff1a;[链接文字](./相对路径) 查找&#xff1a;\[\[(.*?)\]\] 替换&#xff1a;[$1]\(./$1\) 或替换&#xff1a;**[$1]\(./$1\)** &#xff08;码云的超链接&#xff0c;很…

实战18-Card封装

import Card from ../../components/Card/Index; import rvp from ../../utils/resposive/rvIndex;Component export default struct DomesticService {build() {Column() {Card() {//默认插槽Text("DomesticService")}}.width(100%).margin({ top: rvp(43) })} } im…

2024 Python3.10 系统入门+进阶(十五):文件及目录操作

目录 一、文件IO操作1.1 创建或打开文件1.2 读取文件1.2.1 按行读取1.2.2 多行读取1.2.3 完整读取 1.3 写入文件1.3.1 写入字符串1.3.2 写入序列 1.4 上下文管理1.4.1 with语句的使用1.4.2 上下文管理器(拓展----可以学了面向对象之后再回来看) 1.5 文件的遍历 二、os.path模块…

大语言模型-教育方向数据集

大语言模型-教育方向数据集 编号论文数据集1Bitew S K, Hadifar A, Sterckx L, et al. Learning to Reuse Distractors to Support Multiple-Choice Question Generation in Education[J]. IEEE Transactions on Learning Technologies, 2022, 17: 375-390.Televic, NL, https…

79页 PPT华为项目管理经典培训教材(高级)

读者朋友大家好&#xff0c;最近有会员朋友咨询晓雯&#xff0c;需要《79页PPT华为项目管理经典培训教材》资料&#xff0c;欢迎大家文末扫码下载学习。 一、华为项目管理理念方法 &#xff08;一&#xff09;项目管理基本概念与方法 项目启动 明确项目目标&#xff1a;华为…

SAP B1 流程实操 - 营销单据销售部分(上)

背景 在 SAP B1 中&#xff0c;最重要的模块就是【销售】&#xff0c;企业可能不涉及生产和库存&#xff08;贸易公司&#xff09;&#xff0c;甚至不涉及采购&#xff08;服务业&#xff09;&#xff0c;但是一定会有基本的 销售。本文中我们讲解 销售 模块的基本核心&#x…