如何在运行时确定对象类型(RTTI)

聚美微品

聚美微品

2016-01-29 12:19

如何在运行时确定对象类型(RTTI),如何在运行时确定对象类型(RTTI)

如何在运行时确定对象类型(RTTI)

作者:NorthTibet

(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/cyuyanjiaocheng/)



    RTTI 是“Runtime Type Information”的缩写,意思是:运行时类型信息。它提供了运行时确定对象类型的方法。本文将简略介绍 RTTI 的一些背景知识、描述 RTTI 的概念,并通过具体例子和代码介绍什么时候使用以及如何使用 RTTI;本文还将详细描述两个重要的 RTTI 运算符的使用方法,它们是 typeid 和 dynamic_cast。
    其实,RTTI 在C++中并不是什么新的东西,它早在十多年以前就已经出现了。但是大多数开发人员,包括许多高层次的C++程序员对它并不怎么熟悉,更不用说使用 RTTI 来设计和编写应用程序了。
    一些面向对象专家在传播自己的设计理念时,大多都主张在设计和开发中明智地使用虚拟成员函数,而不用 RTTI 机制。但是,在很多情况下,虚拟函数无法克服本身的局限。每每涉及到处理异类容器和根基类层次(如 MFC)时,不可避免要对对象类型进行动态判断,也就是动态类型的侦测。如何确定对象的动态类型呢?答案是使用内建的 RTTI 中的运算符:typeid 和 dynamic_cast。
    首先让我们来设计一个类层次,假设我们创建了某个处理文件的抽象基类。它声明下列纯虚拟函数:open()、close()、read()和 write():

class File{public: virtual int open(const string & filename)=0; virtual int close(const string & filename)=0; // virtual ~File()=0; // 记住添加纯虚拟析构函数(dtor)};
现在从 File 类派生的类要实现基类的纯虚拟函数,同时还要提供一些其他的操作。假设派生类为 DiskFile,除了实现基类的纯虚拟函数外,还要实现自己的flush()和defragment()操作:
class DiskFile: public File{public: int open(const string & filename); // 实现其他的纯虚拟函数    ...... // 自己的专有操作 virtual int flush(); virtual int defragment();};    
接着,又从 DiskFile 类派生两个类,假设为 TextFile 和 MediaFile。前者针对文本文件,后者针对音频和视频文件:
class TextFile: public DiskFile{  // ......  int  sort_by_words();};class MediaFile: public DiskFile{  //......};        
我们之所以要创建这样的类层次,是因为这样做以后可以创建多态对象,如:
File *pfile; // *pfile的静态类型是 Fileif(some_condition)  pfile = new TextFile; // 动态类型是 TextFileelse  pfile = new DiskFile; // 动态类型是 DiskFile       
    假设你正在开发一个基于图形用户界面(GUI)的文件管理器,每个文件都可以以图标方式显示。当鼠标移到图标上并单击右键时,文件管理器打开一个菜单,每个文件除了共同的菜单项,不同的文件类型还有不同的菜单项。如:共同的菜单项有“打开”“拷贝”、和“粘贴”,此外,还有一些针对特殊文件的专门操作。比如,文本文件会有“编辑”操作,而多媒体文件则会有“播放”菜单。为了使用 RTTI 来动态定制菜单,文件管理器必须侦测每个文件的动态类型。利用 运算符 typeid 可以获取与某个对象关联的运行时类型信息。typeid 有一个参数,传递对象或类型名。因此,为了确定 x 的动态类型是不是Y,可以用表达式:typeid(x) == typeid(Y)实现:
#include <typeinfo // typeid 需要的头文件void menu::build(const File * pfile){ if (typeid(*pfile)==typeid(TextFile)) {  add_option("edit");  } else if (typeid(*pfile)==typeid(MediaFile)) { add_option("play");  }}      
    使用 typeid 要注意一个问题,那就是某些编译器(如 Visual C++)默认状态是禁用 RTTI 的,目的是消除性能上的开销。如果你的程序确实使用了 RTTI,一定要记住在编译前启用 RTTI。使用 typeid 可能产生一些将来的维护问题。假设你决定扩展上述的类层次,从MediaFile 派生另一个叫 LocalizeMedia 的类,用这个类表示带有不同语言说明文字的媒体文件。但 LocalizeMedia 本质上还是个 MediaFile 类型的文件。因此,当用户在该类文件图标上单击右键时,文件管理器必须提供一个“播放”菜单。可惜 build()成员函数会调用失败,原因是你没有检查这种特定的文件类型。为了解决这个问题,你必须象下面这样对 build() 打补丁:
void menu::build(const File * pfile){ //......  else if (typeid(*pfile)==typeid(LocalizedMedia)) {  add_option("play");   }}     
    唉,这种做法真是显得太业余了,以后每次添加新的类,毫无疑问都必须打类似的补丁。显然,这不是一个理想的解决方案。这个时候我们就要用到 dynamic_cast,这
展开更多 50%)
分享

猜你喜欢

如何在运行时确定对象类型(RTTI)

C语言教程 C语言函数
如何在运行时确定对象类型(RTTI)

如何使程序在运行时自动注册ActiveX控件

编程语言 网络编程
如何使程序在运行时自动注册ActiveX控件

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

JScript 运行时错误

编程语言 网络编程
JScript 运行时错误

运行时生成控件

Delphi
运行时生成控件

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

在.NET运行时了解类型信息(2)

电脑网络
在.NET运行时了解类型信息(2)

在.NET运行时了解类型信息(3)

电脑网络
在.NET运行时了解类型信息(3)

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

java在Linux下的web应用(一)

java在Linux下的web应用(一)

CSS滤镜:概述

CSS滤镜:概述
下拉加载更多内容 ↓