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

C++运行时类型识别

C++运行时类型识别

简介

运行时类型识别是C++提供的一种机制,允许程序在运行时获取对象的实际类型信息,而非仅依赖编译时的静态类型。这一特性主要解决多态场景下,基类指针/引用指向派生类对象时,无法直接确定其真实类型的问题(如Base * b = new Derived;中,b的声明类型是Base,但实际指向Derived对象

typeid的介绍

typeid是C++的运行时类型识别的关键字,用于获取对象或表达式的类型信息,返回一个const std::type_info&对象,它主要用于多态场景中确定对象的实际类型

  • 基本语法:typeid(表达式)或typeid(类型名),在使用时需要调用头文件<typeinfo>

  • 返回值:const std::type_info&,在不同编译环境下的输出内容可能会有所不同

typeid的用法多样,在visual stdio中可以根据编译器建议发现typeid的多种用法形式

在这里我们仅介绍使用频率最高的用法

#include <typeinfo>#include <iostream>​using namespace std;​int main(){int a = 19;//不同编译器输出结果可能不同cout << typeid(a).name() << endl;cout << typeid(int).name() << endl;}

visual studio code输出结果

visual studio输出结果

可以看出在不同编译环境下的输出格式并不相同,后续为了能够直观的感受程序输出因此都展示visual studio的输出结果

核心作用

  • 识别多态对象的实际类型:对于基类指针/引用指向派生类对象的场景,typeid会返回的类型(需要确保基类又虚函数)

  • 比较类型是否相同:type_info重载了操作符==!=通过==!=比较两个type_info对象是否相等,不等,函数name()返回类型值名称

#include <typeinfo>#include <iostream>​using namespace std;​//基类class Base{virtual void a(){​}};​class Derived : public Base{​};​int main(){Base* b = new Derived();cout << typeid(*b).name() << endl;delete b;return 0;​}​

输出结果

结合上述一系列操作,我们还可以结合指针实现一些复杂操作

#include <typeinfo>#include <iostream>​using namespace std;​class A{public:virtual void func(){cout << "A" << endl;}};​class B : public A{public:void func(){cout << "B" << endl;}};​void test(A* pa){//通过typeid做类型检查if (typeid(*pa).name() == typeid(B).name()){pa->func();}}​int main(){B * pb;pa = &b;pa->func();​//传入对象为B的实例化成员test(pa);//输出指针的类型cout << typeid(pa).name() << endl;//输出指针指向的对象类型cout << typeid(*pa).name() << endl;return 0;​}

输出结果

上述代码中我们实现了通过指针来输出指针类型和指针指向类型,也实现了通过类成员的类型作为条件判断调用不同类内的函数

转型操作

向上转型操作在之前就提到过,这也是C++中的一大特征呢,允许派生类直接给基类赋值,我们在操作时其实也就相当于在隐式调用static_cast关键字

static_cast关键字介绍

基本语法
//基本数据类型转换目标类型 变量 = static_cast<目标类型>(源表达式);//向上转型基类指针/引用 = static_cast<基类类型*>(派生类指针引用);//向下转型派生类指针/引用 = static_cast<派生类类型*>(基类指针/引用);

static_cast是C++中最常用的静态类型转换关键字,用于在编译期完成类型转换,适用于多种场景

在这里我们仅介绍与C++转型操作有关的使用场景

向上转型
class Base{......;};class Derived : public Base {};​Derived d;//派生类->基类Base * pb = static_cast<Base*>(&d);

当然static_cast关键字还能实现向下转型操作,但是我们并不提倡这种做法,因为static_cast关键字并不能提供类型检查,所以使用static_cast实现向下转型是一种很危险的操作

#include <typeinfo>#include <iostream>​using namespace std;​class A{public:virtual void func(){cout << "A" << endl;}};​class B : public A{public:void func(){cout << "B" << endl;}};​​int main(){A a;B b;​A * pa = &a;B * pb = &b;​//向上转型操作a = static_cast<A>(b);pa = static_cast<A*>(pb);​//向下转型操作//引发报错:基类对象不能直接赋值给派生类对象b = a;//引发报错:基类对象不能直接赋值给派生类指针pb = pa;//引发报错:不能直接将类对象转化为派生类对象b = static_cast<B>(a);//不会引发报错,但是存在潜在危险,不能忽视pb = static_cast<B*>(pa);​return 0;}

dynamic_cast关键字介绍

操作限制

dynamic_cast关键字就能够实现向下转型的操作,但是在操作时也会受到限制

  • dynamic_cast仅支持两种转换

    1. 基类指针->派生类指针

    2. 基类引用->派生类引用

  • 仅适用于多态类型,即基类必须要包含虚函数

对于上一部分代码中的第45行语句,只要将其中的static_cast关键字转换为dynamic_cast即可完成转换

语法形式:
//基础语法模板dynamic_cast<目标类型>(源对象)//指针类型转换目标类型指针 = dynamic_cast<目标类型*>(源指针);//引用类型转换目标类型引用 = dynamic_cast<目标类型&>(源引用);

失败返回值:
  • 若对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针

  • 若对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用

类型检查
void test(A * pa){//判断传入对象是否为B类型B *pb = dynamic_cast<B *>(pa);​//如果不等于空指针,则表明转换成功if(pb != nullptr){ pb->func();}}

对比

特性static_castdynamic_cast
检查时机编译期(无运行时检查)运行时(通过RTTI机制检查类型兼容性)
向下转型风险可能产生不安全的转换(如基类指针转派生类)若转换不安全,返回nullptr(指针)或抛异常(引用
类型要求无需多态(类无需虚函数)必须多态(基类至少包含一个虚函数)
http://www.dtcms.com/a/361737.html

相关文章:

  • k8s知识点汇总2
  • Java 加载自定义字体失败?从系统 fontconfig 到 Maven 损坏的全链路排查指南
  • 基于 C 语言的网络单词查询系统设计与实现(客户端 + 服务器端)
  • 适合工程软件使用的python画图插件对比
  • Maven - Nexus搭建maven私有仓库;上传jar包
  • 20250829的学习笔记
  • OPENCV 基于旋转矩阵 旋转Point2f
  • 代码随想录二刷之“回溯”~GO
  • 机器翻译:python库translatepy的详细使用(集成了多种翻译服务)
  • Spring框架入门:从IoC到AOP
  • 爬虫实战练习
  • 如何在Github中创建仓库?如何将本地项目上传到GitHub中?
  • IDEA Spring属性注解依赖注入的警告 Field injection is not recommended 异常解决方案
  • Python绘制多彩多角星实战
  • MyBatis 性能优化最佳实践:从 SQL 到连接池的全面调优指南
  • 链表相关OJ题
  • MongoDB 备份与恢复:mongodump 和 mongorestore 实战
  • NestJS 3 分钟搭好 MySQL + MongoDB,CRUD 复制粘贴直接运行
  • Flutter Container 阴影设置指南 2025版
  • Flutter 完全组件化的项目结构设计实践
  • 复刻elementUI的步骤条Steps
  • 【架构师干货】系统架构设计
  • Pytorch的CUDA版本安装使用教程
  • XGBoost学习笔记
  • docker 数据管理
  • 徐州服务器:机柜租用具体包含哪些内容?
  • 『Java』把Java项目打成Jar包,并引用项目外的Jar依赖
  • Spring Boot 常用注解有哪些?
  • 【MySQL】进阶技术详解
  • 机器学习-时序预测2