C++运行时类型识别RTTI
C++技能 runtime type identification(RTTI)
运行时类型识别
在使用多态的时候经常用到。本文将会介绍RTTI的几个特征。
1. 运行时类型转换
下面的程序模仿了dynamic_cast<type_id>()类型转化符号,根据每个类的id来判断当前的类型,如果id不匹配,则调用dynacast函数会转化失败
#include <iostream>
#include<vector>
using namespace std;//base class
class Security{
protected:enum{BASEID = 0};public:virtual ~Security(){}virtual bool isA(int id){return id == BASEID;}
};///继承基类
class Stock : public Security{typedef Security Super;
protected:enum{ OFFSET = 1, TYPEID = BASEID + OFFSET};
public:bool isA(int id){return id == TYPEID || Super::isA(id);}//类型转换--通过检查id来判断,基类的id = 0,stock id = 1,如果当前id = stock id,则允许向下转换,否则返回NULL static Stock* dynacast(Security* s){return (s->isA(TYPEID)) ? static_cast<Stock*>(s) : 0;}
};//继承了基类
class Bond : public Security{typedef Security Super;
protected:enum{ OFFSET = 2, TYPEID = BASEID + OFFSET};
public:bool isA(int id){return id == TYPEID || Super::isA(id);}static Bond* dynacast(Security* s){return (s->isA(TYPEID)) ? static_cast<Bond*>(s) : 0;}
};//继承了基类
class Investment : public Security{typedef Security Super;
protected:enum{ OFFSET = 3, TYPEID = BASEID + OFFSET};
public:bool isA(int id){return id == TYPEID || Super::isA(id);}static Investment* dynacast(Security* s){return (s->isA(TYPEID)) ? static_cast<Investment*>(s) : 0;}void special(){cout << "special Investment function\n";}
};//基类的孙子类
class Metal : public Investment{typedef Security Super;
protected:enum{ OFFSET = 4, TYPEID = BASEID + OFFSET};
public:bool isA(int id){return id == TYPEID || Super::isA(id);}static Metal* dynacast(Security* s){return (s->isA(TYPEID)) ? static_cast<Metal*>(s) : 0;}
};int main(){vector<Security*> portfolio;//基类指向派生类们 portfolio.push_back(new Metal);portfolio.push_back(new Investment);portfolio.push_back(new Bond); portfolio.push_back(new Stock);//for(vector<Security*>::iterator it = portfolio.begin(); it != portfolio.end(); it++){Investment* cm = Investment::dynacast(*it);//指针转化if(cm)cm->special();elsecout << "not an Investment\n";} Security* sp = new Metal;Investment* cp = Investment::dynacast(sp);//根据多态理论调用对于的dynacast ,这里调用metal类的isAif(cp) cout << "it's a Investment\n";Metal* mp = Metal::dynacast(sp);//转化成功 if(mp) cout << "it's a metal\n";//释放内存for(vector<Security*>::iterator it = portfolio.begin(); it != portfolio.end(); it++){delete *it;} return 0;
}上面是指针的转化,如果使用dynamic_cast程序会简短很多,
#include <iostream>
#include<vector>
using namespace std;//base class
class Security{
public:virtual ~Security(){}
};///继承基类
class Stock : public Security{
};//继承了基类
class Bond : public Security{
};//继承了基类
class Investment : public Security{
public:void special(){cout << "special Investment function\n";}
};//基类的孙子类
class Metal : public Investment{
};int main(){vector<Security*> portfolio;//基类指向派生类们 portfolio.push_back(new Metal);portfolio.push_back(new Investment);portfolio.push_back(new Bond); portfolio.push_back(new Stock);//for(vector<Security*>::iterator it = portfolio.begin(); it != portfolio.end(); it++){Investment* cm = dynamic_cast<Investment*>(*it);//指针转化if(cm)cm->special();elsecout << "not an Investment\n";} Security* sp = new Metal;//转化成功 Investment* cp = dynamic_cast<Investment*>(sp);if(cp) cout << "it's a Investment\n";Metal* mp = dynamic_cast<Metal*>(sp);//转化成功 if(mp) cout << "it's a Metal\n";//释放内存for(vector<Security*>::iterator it = portfolio.begin(); it != portfolio.end(); it++){delete *it;} return 0;
}dynamic_cast要求多态,还好这里的基类的析构是虚函数,因此可以使用 dynamic_cast。另外dynamic_cast只能做指针或者引用的转化
如果是普通的类型转化,则无法用是否为空指针来判断,这时可以用异常处理,如果无法转化,dynamic_cast会抛出异常。
2.typedid操作符
typeid可以获取对象运行时的信息,他会返回一个type_info对象,该对象记录了和这个对象有关的应用信息,比如:
这个对象是多态的,则它将会给出那个应用的大部分派生类信息;否则就给出静态信息,typeid操作符的一个用途是获得一个对象的动态类型的名称
输出结果和编译器有关,有的直接输出名字,有的输出pk什么的,p代表指针,k代表const修饰符
#include <iostream>
#include<vector>
#include<typeinfo>
using namespace std;struct PolyBase{virtual ~PolyBase(){}
}; struct PolyDer : public PolyBase{PolyDer(){}
};struct NonPolyBase{
};struct NonPolyDer : public NonPolyBase{NonPolyDer(int){ }
};int main(){const PolyDer pd;const PolyBase* ppd = &pd;//父类指向子类cout << typeid(ppd).name() << endl;//输出父类自己的名字 cout << typeid(*ppd).name() << endl; //输出子类名称 cout << boolalpha << (typeid(*ppd) == typeid(pd)) << endl;//输出true const NonPolyDer npd(1);const NonPolyBase* nppd = &npd;cout << typeid(nppd).name() << endl;//输出父类 cout << typeid(*nppd).name() << endl; //输出父类 cout << boolalpha << (typeid(*nppd) == typeid(npd)) << endl;//false int i;cout << typeid(i).name() << endl; return 0;
}对于第一种含有虚函数,和第二种不含有虚函数是完全不同的。因为typeid对多态敏感。
使用指针的时候,输出的是指针的静态类型,当调用对象解析的时候,则会输出动态类型
而对于不含虚函数的类,则不会有变化,两次输出都是父类的名字,typeid也支持内置的类型
typeid不支持赋值操作,也没用可供访问的构造函数
3.继承体系的中间层次的转化
比如有这么一个继承体系
class B1{virtual ~B1(){}};
class B2{virtual ~B2(){}};
class MI : public B1, public B2{};
class Mi2 : public MI{};
那么创建一个Mi2对象,可以转化为MI,B1,B2;
#include <iostream>
using namespace std;class B1{public:virtual ~B1(){}
};class B2{public:virtual ~B2(){}
};class MI : public B1, public B2{};class Mi2 : public MI{};int main(){B2* b2 = new Mi2;Mi2* pmi2 = dynamic_cast<Mi2*>(b2);B1* b1 = dynamic_cast<B1*>(b2);MI* mi = dynamic_cast<MI*>(b2);return 0;
}4 void型指针
不可以把void*和typeid和dynamic_cast联系起来
5.虚基类类型向下转化
当基类是虚基类的时候,c++不允许C语言的默认指针转化,但是可以使用dynamic_cast;
相关文章:
C++运行时类型识别RTTI
C技能 runtime type identification(RTTI) 运行时类型识别在使用多态的时候经常用到。本文将会介绍RTTI的几个特征。1. 运行时类型转换下面的程序模仿了dynamic_cast<type_id>()类型转化符号,根据每个类的id来判断当前的类型,如果id不匹配…...
idea多时编辑多行-winmac都支持
1背景介绍 idea编辑器非常强大,其中一个功能非常优秀,很多程序员也非常喜欢用。这个功能能够大大大提高工作效率-------------多行代码同时编辑 2win 2.1方法1 按住alt鼠标左键上/下拖动即可 这样选中多行后,可以直接多行编辑。 优点&a…...
BI是报表?BI是可视化?BI到底是什么?
很多企业认为只要买一个前端商业智能BI分析工具就可以解决企业级的商业智能BI所有问题,这个看法实际上也不可行的。可能在最开始分析场景相对简单,对接数据的复杂度不是很高的情况下这类商业智能BI分析工具没有问题。但是在企业的商业智能BI项目建设有一…...
Python基础-数据类型之元组
一、元组的定义 nums (1, 2, 3, 4, 5) 元组是序列的其中一种,每个元素都以逗号分隔,用()包围。 当元组中只有一个元素时,需要在元素后面加逗号分隔,nums (1,),否则括号会被当成运算符 nums (1) print(type(nums…...
大数据面试小抄
项目地址:https://github.com/GTyingzi/BigDATA 该项目是自己在学习大数据过程中整理、总结下来的一份面试小抄。涵盖Hadoop、Spark、Flink、Hive、HBae、Kafka、ES、Zookeeper等。 开源给大家,若感觉不错欢迎star~ 摘取Flink部分如下文章目录FlinkFli…...
Vue:(三十一)Vue封装的过度与动画
上一篇订阅与发布不够过瘾,接着再来一篇,come on!!!作用:在插入、更新或移除DOM元素时,在合适的时候给元素添加样式类名写法:过度:元素进入的样式:v-enter&am…...
文本处理:字符串替换
方法1:str.replace str.replace(old, new[, count]) Return a copy of the string with all occurrences of substring old replaced by new. If the optional argument count is given, only the first count occurrences are replaced. 该方法逻辑大致如下所示&am…...
python 调用 dll 出现精度问题
问题:python 在调用dll 的时候出现了精度问题 总结:使用decimal库进行转换就可以正常传递。 ‘ 心急的朋友可以略过下文了。 心急的朋友可以略过下文了。 心急的朋友可以略过下文了。 心急的朋友可以略过下文了。 ’ 遇到的问题具体情况 dll 生成函数…...
STL讲解——模拟实现string
STL讲解——模拟实现string 经典的string类问题 大厂在面试中,面试官总喜欢让学生自己来模拟实现string类,最主要是实现string类的增、删、查、改、构造、拷贝构造、赋值运算符重载以及析构函数。大家看下自己可不可以写一个string类? cla…...
CDH 6.3.2 升级Hive 2.3.9
升级背景 DolphinScheduler 3.1.1安装好后,其源码中集成的是Hive 2.1.1,版本太低,当在数据中心连接Hive数据源时报错,所以升级CDH自带的Hive为2.3.9版本。 一、准备工作 1、下载hive2.3.9并解压 下载地址:http://a…...
距离不是拦截我们前进的主因,与社科院杜兰金融硕士一起奔赴山海
最近有咨询社科院杜兰金融管理硕士项目的同学反馈他在西安,读研来北京上课太远了。一直在纠结要不要申请,其实距离不是问题,相向而行才是关键。在项目就读的同学好多也是来自外地,他们克服了种种困难来到项目学习,就是…...
【SpringBoot】MyBatis-plus 报错 sqlSessionFactory sqlSessionTemplate 最新解决办法
本文针对 MyBatis-plus,对于 MyBatis 报相同的错误,可以看这个大佬的文章:SpringBoot3整合MyBatis报错:Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required 针对报错如下: Property sqlSessionF…...
jsp诊疗预约系统Myeclipse开发mysql数据库web结构java编程计算机网页项目
一、源码特点 jsp诊疗预约系统 是一套完善的web设计系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql,使用jav…...
详解 APISIX Lua 动态调试插件 inspect
作者罗锦华,API7.ai 技术专家/技术工程师,开源项目 pgcat,lua-resty-ffi,lua-resty-inspect 的作者。 原文链接 为什么需要 Lua 动态调试插件? Apache APISIX 有很多 Lua 代码,如何在运行时不触碰源代码的…...
#科研筑基# python初学自用笔记 第五篇 函数
调用函数python有很多内置函数,我们可以直接调用,详见python官方文档:内置函数 — Python 3.11.2 文档,也可以在命令行中输入help(函数名)来查看该函数的使用法则。函数名的本质就是指向一个函数对象的引用,完全可以用…...
设计模式之策略模式
一.基本内容1 . 实例有各种鸭子(野鸭,北京鸭子,水鸭等,鸭子有各种行为,比如飞,叫等显示鸭子的信息传统方法解决:鸭子为抽象类,具体鸭子继承抽象类2.传统方法的不足:其他鸭…...
dbdeployer 使用札记
https://github.com/datacharmer/dbdeployer默认配置文件为当前用户的$HOME/.dbdeployer/config.json作为配置文件,可以通过dbdeplyoer defaults export导出并修改配置或者直接通过dbdeployer defaults update来更新默认文件,配置文件包含MySQL初始信息。…...
MATLAB算法实战应用案例精讲-【图像处理】数字图像模糊化(附Java、python和matlab代码实现)
目录 前言 几个相关概念 噪声 滤波器 算法原理 算法思想 噪...
搭建Hexo博客-第1章-Git和GitHub以及Coding的简单用法
搭建Hexo博客-第1章-Git和GitHub以及Coding的简单用法 搭建Hexo博客-第1章-Git和GitHub以及Coding的简单用法 Coding GitHub Hexo Markdown 搭建博客 大家好,这是我第一次写博客。使用 GitHub Hexo 创建最基本的博客很容易,网上有很多现成的教程。…...
【C++修行之路】C/C++内存管理
文章目录程序区域内存划分C语言动态内存分配:new和delete:new、delete和malloc、free的区别:程序区域内存划分 C/C程序内存区域划分非常相似。 C语言动态内存分配: malloc、calloc、realloc都是C语言动态开辟内存的常用函数 其中 malloc 开…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
智能体革命:企业如何构建自主决策的AI代理?
OpenAI智能代理构建实用指南详解 随着大型语言模型(LLM)在推理、多模态理解和工具调用能力上的进步,智能代理(Agents)成为自动化领域的新突破。与传统软件仅帮助用户自动化流程不同,智能代理能够自主执行工…...
篇章一 论坛系统——前置知识
目录 1.软件开发 1.1 软件的生命周期 1.2 面向对象 1.3 CS、BS架构 1.CS架构编辑 2.BS架构 1.4 软件需求 1.需求分类 2.需求获取 1.5 需求分析 1. 工作内容 1.6 面向对象分析 1.OOA的任务 2.统一建模语言UML 3. 用例模型 3.1 用例图的元素 3.2 建立用例模型 …...
