C++运行时类型识别(RTTI)的用途:安全的下行转换和异常处理
cac55 2024-09-20 13:03 41 浏览 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-
相关推荐
- 小车五位自动循环往返控制_小车自动往返控制系统
-
需求描述:用三相异步电动机拖动一辆小车在A、B、C、D、E五点之间自动循环往返运行,小车初始在A点,按下启动按钮,小车依次前进到B、C、D、E点,并分别停止2s返回到A点停止。按下停止...
- 自动灌溉系统_自动灌溉系统by
-
需求描述:PLC时钟设定每日6:00、18:00自动启动灌溉系统,每次运行15分钟后停止;非定时时段按下手动灌溉按钮,立即启动并运行15分钟;土壤湿度传感器检测到湿润时,跳过本次定时灌溉...
- 主板ERP开启还是关闭好_主板设置erp是什么
-
主板功能的开启与关闭,本质是在“节能环保”和“使用便利”之间做选择。为帮你快速决策,先给出直接结论,再深入解析原理、影响及操作步骤,让你根据自身需求精准设置。一、直接结论:ERP功能如何选?...
- 新电脑必做5项设置!做完再玩,流畅安全多用三年
-
刚拿到新电脑,兴奋之余先别急着开机畅玩!做好以下这5大设置,能让你的爱机长期保持流畅如新,安全又省心。尤其是最后一招,很多老用户都不知道!1关闭隐私常规,杜绝数据偷跑新电脑首次开机进行系统初始化时,...
- 属于 PHP 开发者的 Supervisor 实用指南
-
属于PHP开发者的Supervisor实用指南在PHP开发中,我们经常需要运行一些后台进程:队列处理、长时间运行的脚本、WebSocket服务器等。这些进程可能会因为各种原因意外退出,手...
- 领导半夜12点微信派活?三句高情商回复,反手拿捏让他不敢再烦
-
友友们大家来啦!今天来和大家一起分享精彩话题老规矩先点赞再看文!0102别在这里害人了,现在能保住工作就烧高香了,再得瑟,明天早上去办离职0304很简单,把他一起拉上,每半小时打电话或语音汇报,一两次...
- "零点黑科技!硬盘自动备份+离线神操作,服务器数据安全躺赢"
-
公司有一台服务器,数据库需要每天零点进行数据库备份,要求在本机备份一次,再在移动硬盘上异地备份一次。备份完成后硬盘自动离线。具体思路如下:数据库自动备份时间为每天0点,备份过程约需1分钟。0点时开启硬...
- 峰谷电:白天贵、晚上便宜,你家真的适合开通吗?
-
电费单又超预算了?别急着关掉空调,其实你可能错过了一个"电费打折"的机会——峰谷电。它就像电影院的日场和夜场票,白天贵、晚上便宜,聪明利用,电费真的能省下来。一、峰谷电是什么?峰谷电把...
- 电脑开机密码设置全指南:从基础到进阶的安全防护
-
在数字化时代,电脑存储着大量个人隐私和重要数据,设置开机密码是保护信息安全的第一道防线。本文将系统介绍Windows、macOS、Linux三大主流操作系统及BIOS层面的密码设置方法,同时涵盖密码管...
- 自动喷香机_香薰机自动喷香机
-
需求描述:PLC时钟设定每日9:00、14:00、18:00自动启动喷雾,每次喷雾3秒后停止;非定时时段按下手动喷雾按钮,立即喷雾3秒;香薰液缺液传感器检测到液位过低时,停止喷雾并亮报警...
- macbook系统自动启动项在哪里查看
-
了解和管理MacBook的开机自动启动项,是优化系统启动速度和运行效率的好方法。下面我来为你介绍几种查看和管理这些启动项的方法。查看和管理MacBook启动项1.通过系统设置(最简单直接的方法)...
- 想让电脑自己到点开机和关机?这4个超实用的设置方法快收好!
-
嘿,你是不是也经常忙到忘记关电脑?或者早上想用电脑时发现还没开机?别慌,今天我就跟你分享几个超实用的方法,帮你轻松搞定电脑的定时开关机设置。不管你是电脑小白还是有点基础,这篇教程都能让你秒懂操作,省时...
- 定时关机这样操作小白也会 一招设定工作日关机 指定时间关机
-
在日常使用电脑的过程中,我们常常会遇到这样的情况:晚上睡觉前忘记手动关机,导致电脑整夜运行,既浪费电又缩短硬件寿命;或者在下载大文件时,需要等待很长时间才能完成,却不能一直守在电脑前,下载完成后也无法...
- 日本无线电操作证试题,这些问题你能答的上来吗?
-
一直以来,我们对于日本的业余无线电的印象都停留在“操作能力强,爱好者数目众多”上,然而我们对于他们的业余无线电体系所知甚少。日本业余无线电操作证的等级分作四级,最基本的四级操作证书具有8MHz以下、2...
- 你知道吗?单边带信号就像DNA分子一样!
-
我们在准备B级操作证书的过程中,避免不了的要接触到一个新的名词——SSB。单边带是传统AM模式的一种特殊的形式,在传送相同的信息的过程中,其占用的带宽仅为AM模式的一半,那么SSB模式到底是怎样的一种...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 如何绘制折线图 (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)