一、RTTI概述

RTTI的功能由两个运算符实现,一个是typeid,用来返回表达式的类型;另一个是dynamic_cast,作用是将基类的指针或引用安全地转为子类的指针或引用

二、typeid

typeid的表达式形式是typeid(e),e可以是任意表达式或者类型,typeid的结果是个const对象的引用,该对象的类型是标准库type_info或type_info的子类,type_info类中有个name成员函数,返回值是个表示类型名字的字符串,所以typeid的结果可通过name方法查看类型名字

当一个对象中没有虚函数时,typeid得到的时运算对象的静态类型,如果有虚函数,那么,typeid得到的时运算对象的动态类型

示例

class base
{
public:base(){}virtual ~base(){}
};class derive:public base
{
public:derive(){}~derive(){}
};int main(int argc, char const *argv[])
{derive *dp=new derive();base *bp=dp;if (typeid(*dp)==typeid(*bp)) {cout<<"typeid(*dp)==typeid(*bp)"<<endl;cout<<typeid(*dp).name()<<","<<typeid(*bp).name()<<endl;}else {cout<<"typeid(*dp)!=typeid(*bp)"<<endl;cout<<typeid(*dp).name()<<","<<typeid(*bp).name()<<endl;}return 0;
}

如果把基类中的virtual关键字去掉,输出结果如下

因为没有虚函数,所以typeid解析的是bp的静态类型

typeid一般作用于对象,所以typeid中的表示是指针的解引用而不是指针。如果typeid作用于指针,无论是否有虚函数,typeid的结果都是指针的静态类型

将上述代码中的main函数修改

int main(int argc, char const *argv[])
{derive *dp=new derive();base *bp=dp;if (typeid(dp)==typeid(bp)) {cout<<"typeid(dp)==typeid(bp)"<<endl;cout<<typeid(dp).name()<<","<<typeid(bp).name()<<endl;}else {cout<<"typeid(dp)!=typeid(bp)"<<endl;cout<<typeid(dp).name()<<","<<typeid(bp).name()<<endl;}return 0;
}

输出结果如下

上述代码中,if分支永远不会执行,因为typeid作用于指针,结果都是静态类型

如果typeid作用于指针,那么,当执行typeid(p)时,指针p可以无效;

int main(int argc, char const *argv[])
{derive *dp=new derive();base *bp=nullptr;//空指针if (typeid(dp)==typeid(bp)) {cout<<"typeid(dp)==typeid(bp)"<<endl;cout<<typeid(dp).name()<<","<<typeid(bp).name()<<endl;}else {cout<<"typeid(dp)!=typeid(bp)"<<endl;cout<<typeid(dp).name()<<","<<typeid(bp).name()<<endl;}return 0;
}

但是如果执行typeid(*p),那么指针必须有效,否则会抛出一个bad_typeid异常

int main(int argc, char const *argv[])
{derive *dp=new derive();base *bp=nullptr;if (typeid(dp)==typeid(*bp)) {cout<<"typeid(dp)==typeid(bp)"<<endl;cout<<typeid(dp).name()<<","<<typeid(*bp).name()<<endl;}else {cout<<"typeid(dp)!=typeid(bp)"<<endl;cout<<typeid(dp).name()<<","<<typeid(*bp).name()<<endl;}return 0;
}

在运行时执行typeid(*bp),对bp进行解引用,而bp是个空指针,所以抛出异常

typeid一般用于比较两个对象的类型是否相等

三、dynamic_cast

dynamic_cast中尖括号中只能是指针或者引用,用在继承体系中类对象的转换(所以不能用于内置类型的转化)。因为dynamic_cast执行的强转发生在运行时,所以可能耗费较大的运行成本,所以,在对效率要求较高的程序中不要频繁使用dynamic_cast。dynamic_cast 转换成功的话,返回的是指向类的指针或引用,否则返回 nullptr。

因为dynamic_cast中尖括号中只能是指针或者引用,所以,dynamic_cast有两种形式:1、dynamic_cast<type*>(e)。2.dynamic_cast<type&>(e)。

dynamic_cast用于向上转换(子类指针或引用转父类指针或引用)时,dynamic_cast和static_cast是一样的。

dynamic_cast用于向下转换(父类指针或引用转子类指针或引用)时,dynamic_cast会进行运行时类型检查,因此,dynamic_cast比static_cast更安全。 向下转换是否成功与指针或引用指向的实际对象有关,要转换的指针指向对象的实际类型与转换以后的对象类型要相同,否则转换失败。

当基类的指针或者引用指向子类对象时,使用dynamic_cast时,基类中一定要有虚函数,否则无法编译通过。这是因为运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表。

dynamic_cast中的e和type的关系通常有三种情况:1、e的类型是type的子类。2、e的类型是type的基类。3、e的类型就是type。

示例1:e的类型就是type、e的类型是type的基类

class base
{
public:base(){}~base(){}void func(){cout<<__func__<<"in base"<<endl;}
};class derive:public base
{
public:derive(){}~derive(){}void func(){cout<<__func__<<"in derive"<<endl;}
};int main(int argc, char const *argv[])
{base *pb=new base();derive *pd=new derive();base *pb2=dynamic_cast<base*>(pb);base *pb3=dynamic_cast<derive*>(pd);pb2->func();pb3->func();
}

这种从子类向基类的转换或者是平转的情况,用不用dynamic_cast的效果都一样

示例2:e的类型是type的子类,基类的指针指向子类对象

int main(int argc, char const *argv[])
{base *pb=new derive();derive *pd=dynamic_cast<derive*>(pb);pd->func();
}

上述代码中,因为基类base不是多态类(没有虚函数),因此无法找到运行是信息进行运行时类型检查,所以,此时即使基类指针指向子类对象,也无法进行dynamic_cast,代码无法通过编译,

将base的析构函数设置为virtual后,代码可以通过编译,运行后,调用子类中的func

示例3:e的类型是type的子类,基类的指针指向基类对象

int main(int argc, char const *argv[])
{base *pb=new base();if (derive *pd=dynamic_cast<derive*>(pb)) {//缩小pd的作用域,即使转换失败,if-else分支之外的代码也无法接触到该指针,比较安全pd->func();}else {cout<<pd<<endl;}
}

此时编译可以通过,但是转换失败,dynamic_cast返回一个空指针,因为要转换的指针指向对象的实际类型与转换以后的对象类型不相同,所以转换失败。所以当基类指针指向基类对象时,使用dynamic_cast向子类转换会失败

使用dynamic_cast作用于引用时的规则和指针一样,只不过要使用try-catch捕获异常

int main(int argc, char const *argv[])
{base t;base &rb=t;try {derive &rd=dynamic_cast<derive&>(rb);}catch(bad_cast) {cout<<"bad_cast"<<endl;}
}

参考

《C++ Primer》

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

C++知识点54——RTTI(运行时类型识别)相关推荐

  1. java 运行时类型_Java基础之RTTI 运行时类型识别

    运行时类型识别(RTTI, Run-Time Type Identification)是Java中非常有用的机制,在Java运行时,RTTI维护类的相关信息. 多态(polymorphism)是基于R ...

  2. 深入浅出MFC学习笔记:MFC六大关键技术仿真之RTTI运行时类型识别

    RTTI(运行时类型识别) 参考文献:深入浅出MFC-侯捷 怎样去构造类别型录网? 一.定义数据结构: 其中pFirstClass指针属于痊愈变量,所以它应该以static修饰之. 而且我们最终希望达 ...

  3. C++ 学习笔记之(19) new、delete表达式、RTTI(运行时类型识别)、枚举、类成员指针、嵌套类、局部类、位域、volatile、extern C

    C++ 学习笔记之(19) new.delete表达式.RTTI(运行时类型识别).枚举.类成员指针.嵌套类.局部类.位域.volatile.extern C C++ 学习笔记之(19) new.de ...

  4. Java RTTI运行时类型识别

    RTTI(Run-Time Type Identification),通过运行时类型信息程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型. RTTI提供了以下两个非常有用的操作 ...

  5. java rtti_举例讲解Java的RTTI运行时类型识别机制

    1.RTTI:运行时类型信息可以让你在程序运行时发现和使用类型信息. 在Java中运行时识别对象和类的信息有两种方式:传统的RTTI,以及反射.下面就来说下RTTI. RTTI:在运行时,识别一个对象 ...

  6. 白话C++系列(27) -- RTTI:运行时类型识别

    http://www.cnblogs.com/kkdd-2013/p/5601783.html RTTI-运行时类型识别 RTTI:Run-Time Type Identification. 那么RT ...

  7. c++远征之多态篇——运行时类型识别(RTTI)

    以下内容源于慕课网的学习整理,如有侵权,请告知删除. 1.RTTI(Run-Time Type Information),运行时类型识别. 涉及typeid.dynamic_cast这两个知识点. R ...

  8. MFC六大核心机制之二:运行时类型识别(RTTI)

    上一节讲的是MFC六大核心机制之一:MFC程序的初始化,本节继续讲解MFC六大核心机制之二:运行时类型识别(RTTI). typeid运算子 运行时类型识别(RTTI)即是程序执行过程中知道某个对象属 ...

  9. RTTI机制(运行时类型识别)

    RTTI机制(运行时类型识别) 在多态里面,基类里的虚函数和派生类里的虚函数形成了遮蔽,这就导致在主程序运行时,有些表达式的类型没有办法确定.必须等到程序运行结束后,根据具体的环境才能确定.看下面的代 ...

  10. C++11 的 运行时类型识别type_info

    一.type_info与typeid 类type_info保存关于类型的特定于实现的信息,包括类型的名称,以及比较两个类型是否相等或排序顺序的方法. 这是typeid操作符返回的类.具有如下特点: ( ...

最新文章

  1. 在iOS中使用tableView
  2. mysql5.6更改datadir数据存储目录
  3. 13.在Ubuntu20.04下,chromium无法输入中文以及如何卸载chromium浏览器
  4. Android深入浅出之Binder机制
  5. Apache Dubbo 被曝出“高危”远程代码执行漏洞
  6. jQuery.ready() 函数详解
  7. 容器精华问答 | 虚拟机和容器的区别是什么?
  8. 【Java】Java 集合 可视化 在线演示 环境
  9. 使用template.js加载后端数据
  10. NSDate 时间戳与字符串转换
  11. 手机qq2008触屏版_手机版卖家中心在哪里
  12. 2021爱分析・中国采购数字化趋势报告
  13. word替换功能 如何将相同的内容,替换为依次排列的数字编号
  14. obs弹幕助手android版,OBS Studio 使用全屏弹幕教程
  15. 动态创建style标签样式
  16. Android TextView中 代码字体加粗方法
  17. Invalid HTTP method: PATCH executing PATCH
  18. Vue实现web端仿网易云音乐 完成大部分功能
  19. IOException parsing XML document from class path resource [applicationContent.xml]; nested exception
  20. 验证集到底有什么作用

热门文章

  1. 区域医疗卫生信息化建设将成投资重点
  2. 构建稳固的、可升缩的CSS框架的八大原则
  3. mysql主从状态异常解决办法
  4. awstats的安装和配置
  5. 使用php+swoole对client数据实时更新
  6. 外包:卡卡软件简要思路
  7. HTTP 错误 500.21 - Internal Server Error
  8. 一文学懂Java泛型,详细而全面,值得收藏~
  9. Scala数值类型转换
  10. Spark2.2.0分布式集群安装(StandAlone模式)