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 开…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...

springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...