C++运行时类型识别(RTTI)的用途:安全的下行转换和异常处理
cac55 2024-09-20 13:03 38 浏览 0 评论
RTTI(Run-Time Type Identification)用途:
① 配合typeid操作符的实现;
② 实现异常处理中catch的类型动态匹配;
③ 实现动态类型转换dynamic_cast;
④ 继承链上的多态;
⑤ 安全的downcast;
The C++ RTTI mechanism provides a type-safe downcast facility but only for those types exhibiting polymorphism (those that make use of inheritance and dynamic binding). How does one recognize this? How can a compiler look at a class definition and determine whether this class represents an independent ADT or an inheritable subtype supporting polymorphism? One strategy, of course, is to introduce a new keyword. This has the advantage of clearly identifying types that support the new feature and the disadvantage of having to retrofit the keyword into older programs.
C++RTTI机制提供了一种类型安全的向下转换工具,但仅适用于那些表现出多态性的类型(那些利用继承和动态绑定的类型)。人们如何认识到这一点?编译器如何查看类定义并确定该类是表示独立的ADT还是支持多态性的可继承子类型?当然,一种策略是引入一个新的关键字。这样做的优点是可以清楚地识别支持新功能的类型,缺点是必须将关键字改装到旧程序中。
An alternative strategy is to distinguish between class declarations by the presence of one or more declared or inherited virtual functions. This has the advantage of transparently transforming existing programs that are recompiled. It has the disadvantage of possibly forcing the introduction of an otherwise unnecessary virtual function into the base class of an inheritance hierarchy. No doubt you can think of a number of additional strategies. This latter strategy, however, is the one supported by the RTTI mechanism. Within C++, a polymorphic class is one that contains either an inherited or declared virtual function.
另一种策略是通过存在一个或多个已声明或继承的虚函数来区分类声明。这具有透明地转换重新编译的现有程序的优点。它的缺点是可能会强制在继承层次结构的基类中引入不必要的虚函数。毫无疑问,你可以想出一些额外的策略。然而,后一种策略是RTTI机制支持的策略。在C++中,多态类包含继承的或声明的虚函数。
From an implementation viewpoint, this strategy has the additional advantage of significantly minimizing overhead. All class objects of polymorphic classes already maintain a pointer to the virtual function table (the vptr). By our placing the address of the class-specific RTTI object within the virtual table (usually in the first slot), the additional overhead is reduced to one pointer per class (plus the type information object itself) rather than one pointer per class object. In addition, the pointer need be set only once. Also, it can be set statically by the compiler, rather than during runtime within the class construction as is done with the vptr.
从实现的角度来看,该策略具有显著最小化开销的额外优势。多态类的所有类对象都已经维护了指向虚拟函数表(vptr)的指针。通过将特定于类的RTTI对象的地址放在虚拟表中(通常在第一个插槽中),额外的开销减少到每个类一个指针(加上类型信息对象本身),而不是每个类对象一个指针。此外,指针只需设置一次。此外,它可以由编译器静态设置,而不是像vptr那样在类构造的运行时进行设置。
class type_info {
public:
virtual ~type_info();
int operator==(const type_info& rhs) const;
int operator!=(const type_info& rhs) const;
int before(const type_info& rhs) const;
const char* name() const;
const char* raw_name() const;
private:
void *_m_data;
char _m_d_name[1];
type_info(const type_info& rhs);
type_info& operator=(const type_info& rhs);
};
The dynamic_cast operator determines at runtime the actual type being addressed. If the downcast is safe (that is, if the base type pointer actually addresses an object of the derived class), the operator returns the appropriately cast pointer. If the downcast is not safe, the operator returns 0. For example, following is how we might rewrite our original cfront downcast. (Of course, now that the actual type of pt can be either a fct or a gen, the preferred programming method is a virtual function. In this way, the actual type of the argument is encapsulated. The program is both clearer and more easily extended to handle additional types. )
dynamic_cast运算符在运行时确定要处理的实际类型。如果向下转换是安全的(即,如果基类型指针实际指向派生类的对象),则运算符返回相应的转换指针。如果下行不安全,则运算符返回0。例如,下面是我们如何重写原始的cfront下行转换。(当然,既然pt的实际类型可以是fct或gen,首选的编程方法是虚拟函数。这样,参数的实际类型就被封装了。程序更清晰,更容易扩展以处理其他类型。)
typedef type *ptype;
typedef fct *pfct;
simplify_conv_op( ptype pt )
{
if( pfct pf = dynamic_cast< pfct >( pt )) {
// ... process pf
}
else { ... }
}
What is the actual cost of the dynamic_cast operation? A type descriptor of pfct is generated by the compiler. The type descriptor for the class object addressed by pt must be retrieved at runtime; it's retrieval goes through the vptr. Here is a likely transformation:
dynamic_ cast操作的实际成本是多少?编译器生成pfct的类型描述符。pt寻址的类对象的类型描述符必须在运行时检索;它的检索通过vptr进行。下面是一个可能的转变:
// access of type descriptor for pt
((type_info*) (pt->vptr[ 0 ]))->_type_descriptor;
type_info is the name of the class defined by the Standard to hold the required runtime type information. The first slot of the virtual table contains the address of the type_info object associated with the class type addressed by pt. The two type descriptors are passed to a runtime library routine that compares them and returns a match or no-match result. Obviously, this is considerably more expensive than a static cast, but considerably less so than an incorrect downcast such as our down-casting a type to a fct when it really addresses a gen.
type_info是由标准定义的类的名称,用于保存所需的运行时类型信息。虚拟表的第一个插槽包含与pt寻址的类类型相关联的type_info对象的地址。这两个类型描述符被传递到运行时库例程,该例程比较它们并返回匹配或不匹配结果。显然,这比静态转换要昂贵得多,但比不正确的向下转换要便宜得多,例如我们将一个gen类型向下转换为一个fct类型时。
Originally, the proposed support for a runtime cast did not introduce any new keywords or additional syntax. The cast
最初,提议的对运行时强制转换的支持没有引入任何新的关键字或附加语法。例如下面这种转换操作:
// original proposed syntax for run-time cast
pfct pf = pfct( pt );
was either static or dynamic depending on whether pt addressed a polymorphic class object. The gang of us at Bell Laboratories (back then, anyway) thought this was wonderful, but the Standards committee thought otherwise. Their criticism, as I understand it, was that an expensive runtime operation looks exactly the same as a simple static cast. That is, there is no way to know, when looking at the cast, whether pt addresses a polymorphic object and therefore whether the cast is performed at compile time or runtime. This is true, of course. However, the same can be said about a virtual function call. Perhaps the committee should also have introduced a new syntax and keyword to distinguish
是静态的还是动态的,取决于pt是否寻址多态类对象。贝尔实验室的一帮人(不管怎么说,当时)认为这很好,但标准委员会却不这么认为。据我所知,他们的批评是,昂贵的运行时操作看起来与简单的静态转换完全相同。也就是说,在查看转换时,无法知道pt是否寻址多态对象,因此无法知道转换是在编译时还是在运行时执行的。当然,这是真的。然而,虚拟函数调用也是如此。也许委员会也应该引入一种新的语法和关键字来区分
pt->foobar();
as a statically resolved function call from its invocation through the virtual mechanism.
是一个静态决议的function call,还是一个虚拟机制的调用操作。
While RTTI as provided by the type_info class is necessary for EH (exception handling) support, in practice it is insufficient to fully support EH. Additional derived type_info classes providing detailed information on pointers, functions, classes, and so on are provided under an EH mechanism. MetaWare, for example, defines the following additional classes:
虽然type_info类提供的RTTI对于EH支持是必要的,但实际上它不足以完全支持EH(异常处理)。在EH机制下提供了其他派生的type_信息类,这些类提供了有关指针、函数、类等的详细信息。例如,MetaWare定义了以下附加类:
class Pointer_type_info: public type_info { ... };
class Member_pointer_info: public type_info { ... };
class Modified_type_info: public type_info { ... };
class Array_type_info: public type_info { ... };
class Func_type_info: public type_info { ... };
class Class_type_info: public type_info { ... };
and permits users to access them. Unfortunately, neither the naming conventions nor the extent of these derived classes is standardized, and they vary widely across implementations.
并允许用户访问它们。不幸的是,这些派生类的命名约定和范围都没有标准化,并且在不同的实现中差异很大。
Although I have said that RTTI is available only for polymorphic classes, in practice, type_info objects are also generated for both built-in and nonpolymorphic user-defined types. This is necessary for EH support. For example, consider
虽然我已经说过RTTI只适用于多态类,但实际上,type_info对象也会为内置类型和非多态用户定义类型生成。这对于EH支持是必要的。例如,考虑
int ex_errno;
...
throw ex_errno;
where a type_info object supporting the int type is generated. Support for this spills over into user programs:
其中生成支持int类型的type_ info对象。对这一点的支持扩展到用户程序中:
int *ptr;
...
if ( typeid( ptr ) == typeid( int* ))
...
Use of typeid( expression ) within a program, such as
在程序中使用typeid(表达式),例如
int ival;
...
typeid( ival ) ... ;
or of typeid( type ), such as
typeid( double ) ... ;
returns a const type_info&. The difference between the use of typeid on a nonpolymorphic expression or type is that the type_info object is retrieved statically rather than at runtime. The general implementation strategy is to generate the type_info object on demand rather than at program outset.
返回常量type_info&。在非多态表达式或类型上使用typeid的区别在于,type_info&对象是静态检索的,而不是在运行时检索的。一般的实现策略是根据需要而不是在程序开始时生成type_info对象。
ref
Stanley B. Lippman 《Inside the C++ Object Model》
https://www.cnblogs.com/malecrab/p/5574070.html
-End-
相关推荐
- Mac电脑强制删除任何软件方法-含自启动应用
-
对于打工者来说,进入企业上班使用的电脑大概率是会被监控起来,比如各种流行的数据防泄漏DLP,奇安信天擎,甚至360安全卫士,这些安全软件你想卸载是非常困难的,甚至卸载后它自己又安装回来了,并且还在你不...
- Linux基础知识 | 文件与目录大全讲解
-
1.linux文件权限与目录配置1.文件属性Linux一般将文件可存取的身份分为三个类别,分别是owner/group/others,且三种身份各read/write/execute等权限文...
- 文件保护不妥协:2025 年 10 款顶级加密工具推荐
-
数据安全无小事,2025年这10款加密工具凭借独特功能脱颖而出,从个人到企业场景全覆盖,第一款为Ping32,其余为国外英文软件。1.Ping32企业级加密核心工具,支持200+文件格...
- 省心省力 一个软件搞定系统维护_省心安装在哪里能找到
-
◆系统类似于我们居住的房间,需要经常打理才能保持清洁、高效。虽然它本身也自带一些清理和优化的工具,但借助于好用的第三方工具来执行这方面的任务,会更让人省心省力。下面笔者就为大家介绍一款集多项功能于一身...
- JAVA程序员常用的几个工具类_java程序员一般用什么软件写程序
-
好的工具做起事来常常事半功倍,下面介绍几个开发中常用到的工具类,收藏一下,也许后面真的会用到。字符串处理:org.apache.commons.lang.StringUtilsisBlank(Char...
- 手工解决Windows10的若干难题_windows10系统卡顿怎么解决
-
【电脑报在线】很多朋友已经开始使用Win10,估计还只是测试版本的原因,使用过程中难免会出现一些问题,这里介绍解决一些解决难题的技巧。技巧1:让ProjectSpartan“重归正途”从10074...
- System32文件夹千万不能删除,看完这篇你就知道为什么了
-
C:\Windows\System32目录是Windows操作系统的关键部分,重要的系统文件存储在该目录中。网上的一些恶作剧者可能会告诉你删除它,但你不应该尝试去操作,如果你尝试的话,我们会告诉你会发...
- Windows.old 文件夹:系统备份的解析与安全删除指南
-
Windows.old是Windows系统升级(如Win10升Win11)或重装时,系统自动在C盘创建的备份文件夹,其核心作用是保留旧系统的文件、程序与配置,为“回退旧系统”提供保...
- 遇到疑难杂症?Windows 10回收站问题巧解决
-
回收站是Windows10的一个重要组件。然而,我们在使用过程中,可能会遇到一些问题。例如,不论回收站里有没有文件,都显示同一个图标,让人无法判别回收站的空和满的真实情况;没有了像Windows7...
- 卸载软件怎么彻底删掉?简单几个步骤彻底卸载,电脑小白看过来
-
日常工作学习生活中,我们需要在安装一些软件程序,但随着软件的更新迭代速度,很多时候我们需要重新下载安装新的程序,这时就需要将旧的一些软件程序进行卸载。但是卸载软件虽然很简单,但是很多小伙伴们表示卸载不...
- 用不上就删!如何完全卸载OneDrive?
-
作为Windows10自带的云盘,OneDrive为资料的自动备份和同步提供了方便。然而,从隐私或其他方面考虑,有些人不愿意使用OneDrive。但Windows10本身不提供直接卸载OneDri...
- 【Linux知识】Linux下快速删除大量文件/文件夹方法
-
在Linux下,如果需要快速删除大量文件或文件夹,可以使用如下方法:使用rm命令删除文件:可以使用rm命令删除文件,例如:rm-rf/path/to/directory/*这个命令会递...
- 清理系统不用第三方工具_清理系统垃圾用什么软件
-
清理优化系统一定要借助于优化工具吗?其实,手动优化系统也没有那么神秘,掌握了方法和技巧,系统清理也是一件简单和随心的事。一方面要为每一个可能产生累赘的文件找到清理的方法,另一方面要寻找能够提高工作效率...
- 系统小技巧:软件卸载不了?这里办法多
-
在正常情况下,我们都是通过软件程序组中的卸载图标,或利用控制面板中的“程序和功能”模块来卸载软件的。但有时,我们也会发现利用卸载图标无法卸载软件或者卸载图标干脆丢失找不到了,甚至控制面板中卸载软件的功...
- 麒麟系统无法删除文件夹_麒麟系统删除文件权限不够
-
删除文件夹方法例:sudorm-rf文件夹名称。删除文件方法例:sudorm-r文件名包括扩展名。如果没有权限,给文件夹加一下权限再删。加最高权限chmod775文件名加可执行权限...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 如何绘制折线图 (52)
- javaabstract (48)
- 新浪微博头像 (53)
- grub4dos (66)
- s扫描器 (51)
- httpfile dll (48)
- ps实例教程 (55)
- taskmgr (51)
- s spline (61)
- vnc远程控制 (47)
- 数据丢失 (47)
- wbem (57)
- flac文件 (72)
- 网页制作基础教程 (53)
- 镜像文件刻录 (61)
- ug5 0软件免费下载 (78)
- debian下载 (53)
- ubuntu10 04 (60)
- web qq登录 (59)
- 笔记本变成无线路由 (52)
- flash player 11 4 (50)
- 右键菜单清理 (78)
- cuteftp 注册码 (57)
- ospf协议 (53)
- ms17 010 下载 (60)