C++RTTI运算符
概述
运行时类型识别(RTTI)两个重要运算符:
- typeid:返回表达式类型。
- dynamic_cast:将基类指针或引用安全转换成派生类的指针或引用。
oop回顾:
- 不存在从基类向派生类的隐式转换。原因是因为派生类对象中包含基类部分和派生类部分,而基类对象中只包含有基类部分。
- 不存在基类指针或引用绑定在一个派生类对象,又将基类转换为派生类。该操作在编译时就会引发错误,原因是编译器无法确定某个特定转换是运行时安全的,其只能检查static type。
dynamic_cast运算符
RTTI运算符中的dynamic_cast就是针对第二点将编译时的检查放在运行时进行。运算符作用于某种类型的指针或引用,且该类型具有虚函数,运算符将使用被绑定对象的dynamic type而非static type。
RTTI运算符使用场景:拥有一个基类指针,但想使用派生类专属的操作(派生类肯定有自己独特的函数而非虚函数,依赖动态类型选择虚函数版本不适合这种情况)。
①dynamic使用形式:
/*type可以是指针、引用、右值引用e的dynamic_type必须是type类型,但是其static type类型可以是type的公有派生类、公有基类或type类型。
*/
type Target = dynamic_cast<type>(e);
②条件中使用dynamic_cast,既可以进行类型转换,又能进行条件检查:
if(Derived* kid = dynamic_cast<Derived*>(father)){//直接使用转换后的kid指针kid->DoSomething();}else{//转换不通过,会返回0cout<< "cast failed" <<endl;
}//引用类型转换失败不会返回0,而是抛出std::bad_cast
使用测试:
class Actor{public:Actor(int Input):Num(Input){}virtual void print()const{cout<< "Actor"<<endl;}void Funtion(){cout<<Num<<endl;}public:int Num;
};
class ActorChild: public Actor{public:ActorChild(int InputFirst,int InputSecond):Actor(InputFirst),ChildNum(InputSecond){}virtual void Print()const override{cout<< "ActorChild"<<endl;}void ChildFuntion(){cout<<ChildNum<<endl;}public:int ChildNum;
};
class Testt:public ActorChild{public:Testt(int InputFirst,int InputSecond):ActorChild(InputFirst,InputSecond){}
};int main()
{//对②的测试,条件中进行类型转换ActorChild A(2,1);Actor* OtherActor = &A;if(ActorChild* Controller = dynamic_cast<ActorChild*>(OtherActor)){//成功转换,并使用了派生类的虚函数Controller->Print();//成功转换,并使用了派生类的专有函数Controller->ChildFuntion();}//Controller->print(); 错误,Controller只在上面的条件块中作用。//对①的测试,e的dynamic type类型不是type类型 Actor* B = new Actor(2);ActorChild* C = new ActorChild(2,2);//对①的测试,e的dynamic type类型不是type类型 Testt* D = new Testt(2,2);Actor* E = D;ActorChild* F = D; if(Testt* ptr = dynamic_cast<Testt*>(B)){}else{cout << "castB failed"<<endl;}if(Testt* ptr = dynamic_cast<Testt*>(C)){}else{cout << "castC failed"<<endl;}if(Testt* ptr = dynamic_cast<Testt*>(D)){}else{cout << "castD failed"<<endl;}if(Testt* ptr = dynamic_cast<Testt*>(E)){}else{cout << "castE failed"<<endl;} if(Testt* ptr = dynamic_cast<Testt*>(F)){}else{cout << "castF failed"<<endl;}
}
/*
output:
ActorChild
1
castB failed
castC failed
*/
typeid运算符
基本使用:
int main()
{ActorChild* A = new ActorChild(1,1);Actor* B = A;//typeid可以作用于指针,但是typeid操作结果返回的是static type。if(typeid(A)==typeid(B)){cout<<"1同一类型"<<endl;}if(typeid(*A)==typeid(*B)){cout<<"2同一类型"<<endl;}//typeid可以作用于指针,但是typeid操作结果返回的是static type。if(typeid(A)==typeid(ActorChild)){cout<<"3同一类型"<<endl;}if(typeid(A)==typeid(ActorChild*)){cout<<"4同一类型"<<endl;}if(typeid(*A)==typeid(ActorChild)){cout<<"5同一类型"<<endl;}
}
/*output:
2同一类型
4同一类型
5同一类型
*/
结论-
- typeid运算对象可以是表达式或类型名。
- typeid运算结果返回一个来自typeinfo中的type_info类常量对象。
- typeid可以作用于指针(更宽泛地说,运算对象不包括包含虚函数的类),typeid操作结果返回的是static type。
- typeid也可以作用于对象,若该对象是包含虚函数的类,则会运算对象的动态类型。
使用场景:为具有继承关系的类实现相等运算符,且是深度比较(类型和成员数据)。在没有RTTI参与下,为什么不使用operator==和equal()虚函数来直接实现相等判断?
class Actor{public:Actor(int Input):Num(Input){}bool operator==(const Actor& Other){ return Num==Other.Num; }private:int Num;
};
class ActorChild: public Actor{public:ActorChild(int InputFirst,int InputSecond):Actor(InputFirst),ChildNum(InputSecond){}bool operator==(const ActorChild& Other){return ChildNum==Other.ChildNum; }private:int ChildNum;
};
仅有operator下,派生类无法直接访问基类私有成员进行比较,故需要借助equal虚函数的帮助。但虚函数形参无法修改,形参为基类只能比较基类部分而派生类部分无法比较,所以运行时调用该函数进行比较行不通。而使用RTTI在operator中先进行类型判断(typeid),然后equal()中再通过dynamic_cast将形参捕获的基类引用进行类型转换,从而实现对派生部分的比较。
class Actor{ public:Actor(int Input):Num(Input){}bool operator==(const Actor& Other){cout<<"operator=="<<endl;//this->equal()为虚调用return typeid(*this)==typeid(Other) && this->equal(Other);} virtual bool equal(const Actor& rhs)const{cout<<"Actor equal"<<endl;return Num==rhs.Num;}protected:int Num;
};class ActorChild: public Actor{public:ActorChild(int InputFirst,int InputSecond):Actor(InputFirst),ChildNum(InputSecond){}virtual bool equal(const Actor& rhs)const override{cout<<"ActorChild equal"<<endl;auto &temp = dynamic_cast<const ActorChild&>(rhs);return ChildNum == temp.ChildNum && Actor::equal(rhs) ;};protected:int ChildNum;
};int main()
{ActorChild* a = new ActorChild(2,2);ActorChild* b = new ActorChild(2,2);ActorChild* c = new ActorChild(1,2);Actor* d = b;Actor* e = c;if(*a==*d){cout << "一样"<<endl;}else{cout << "不一样"<<endl;}if(*a==*e){cout << "一样"<<endl;}else{cout << "不一样"<<endl;}
}
/*
operator==
ActorChild equal
Actor equal
一样
operator==
ActorChild equal
Actor equal
不一样*/
在派生类中比较派生部分,如果想要进一部比较基类部分,则可以使用回避虚函数的机制,通过作用域运算符执行基类的特定版本,该操作适用于派生类虚函数调用其覆盖的基类虚函数版本。
C++RTTI运算符相关推荐
- rtti是什么java_RTTI
RTTI(Run-Time Type Identification),通过运行时类型信息程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型. 中文名 运行时类型识别 外文名 Ru ...
- 如何在运行时确定对象类型(RTTI)
RTTI 是"Runtime Type Information"的缩写,意思是:运行时类型信息.它提供了运行时确定对象类型的方法.本文简略介绍 RTTI 的一些背景知识.描述 RT ...
- Delphi运算符及优先级
单目运算符 (最高优先级) @ 取变量或函数的地址(返回一个指针) not 逻辑取反或按位取反 乘除及按位运算符 * 相乘或集合交集 / 浮点相除 div 整数相除 mod 取模 (整数相除的余数) ...
- 【C++grammar】动态类型转换、typeid与RTTI
目录 动态类型转换 1.为何需要动态类型转换 2.dynamic_cast<>();运算符 3.向上转换和向下转换( Upcasting and Downcasting) 4. 基类对象和 ...
- 计算时间:一个运算符重载示例
题目 今天早上在Priggs的账户上花费2小时35分钟,下午又花费了2小时40分钟,则总共花了多少时间. mytime0.h #ifndef MYTIME0_H #define MYTIME0_Hcl ...
- C++ RTTI 简介
代码编译运行平台:VS2017+Debug+Win32 文章目录 1.typeid 的用法 1.1 type_info 类 1.2 typeid 应用实例 1.2.1 typeid 静态类型判断 1. ...
- -nan(ind) 重载运算符以及结构体排序
一. -nan(ind): nan:not a number:无法得到一个数字 ind:indeterminate: 不确定的 可能情况: 1. 分母为零 2. 对负数开平方 3. 有些编译器在对无穷 ...
- C++知识总结——运算符重载
C++知识总结--运算符重载 3.运算符重载 3.1运算符重载概念 3.2运算符重载规则 3.3运算符重载形式 3.运算符重载 3.1运算符重载概念 C++中预定义的运算符的操作对象只能是基本数据 ...
- C++ RTTI及“反射”技术
RTTI 是"Runtime Type Information"的缩写,意思是:运行时类型信息.它提供了运行时确定对象类型的方法.本文将简略介绍 RTTI 的一些背景知识.描述 R ...
最新文章
- 用电梯服务器怎样解电梯显示E34,默纳克品牌电梯故障代码e41怎么处理
- 虚拟机python建站_搭建本地虚拟服务器linux(CentOS 7)的python虚拟环境(Hyper-V演示)...
- windows笔记-【内核对象线程同步】等待函数
- mysql delimiter
- nyoj 269 VF 动规
- 中移动IM+MM 抢滩移动互联网
- Oracle恢复某个时间之前的数据
- ppt编辑数据链接文件不可用_拷过来的ppt不能编辑 - 卡饭网
- 计算机主板USB接口介绍,如何解决计算机主板USB接口供电不足
- 数据分析之 AB测试(AB Test)
- (转载)虚幻引擎3--12掌握虚幻技术UnrealScript 代理
- c++构造函数的定义
- 如何有效地帮助新人融入项目中
- 下载正版的Windows操作系统和office软件
- 基于MTCNN卷积神经网络的人脸识别
- Fastadmin 阿里云Oss插件的配置
- 数据可视化呈现方式有哪些
- OPC UA协议网关
- 两个案例带你了解 cookie 和 SSL(开心网 jobbole)
- runtime suspend
热门文章
- Revit“原点”、“中心”、“测量点”在哪里?
- 【202203-4】通信管理系统
- 安全产品的核心逻辑-杀毒软件
- 如何使用graphpad做柱形图_Graphpad Prism 8作图教程(2):XY图的属性设置
- xmind8使用甘特图与导出甘特图PDF
- unity2020新特性_Unity Hackweek 2020 –无论我们身在何处,
- 人话解读LGPLv3
- SAP 物料的最小订购量、及舍入值的测试
- 爬虫系列:某家小区房产信息及POI数据获取
- 编写 SQL 查询表格,按创建时间降序排列。