下面这篇文章虽然有点老,但对C++的RTTI基本原理讲的比较透彻。 该文章摘自UMLCHINA网站,是台湾一个群体写的,我根据大家比较熟悉的方式,修改了一些名词的说法,如衍生(派生)等,让大家可以方便的阅读。 C++的 RTTI 观念和用途 物泽C++应用小组 的异常处理(exception handling)需要RTTI﹔最近新推出的C++ 或多或少已提供RTTI。然而,若不小心使用RTTI﹐可能会导致软件弹性的降低。本文将介绍RTTI的观念和近况﹐并说明如何善用它。 什么是RTTI﹖ 关类的结构资料(representational information)。但是﹐这些资料只供编译器(compi ler)使用﹐编译完毕后并未留下来﹐所以在执行时期(at run-time) ﹐无法得知对象的 类资料﹐包括类名称、数据成员名称与类型、函数名称与类型等等。例如﹐两个类﹐其继承关系如下图: 若有如下指令﹕ 在执行时﹐p 指向一个对象﹐但欲得知此对象之类资料﹐就有困难了。同样欲得知q 所参考(reference) 对象的类资料﹐也无法得到。 道指针所指到或参考到的对象类型时﹐该对象有能力来告诉您。 ●类识别(class identification)──包括类名称或ID。 ●继承关系(inheritance relationship)──支持执行时期的「往下变换类型」(downw ard casting)﹐亦即动态变换类型(dynamic casting) 。 在对象数据库存取上﹐还需要下述RTTI﹕ ●对象结构(object layout) ──包括属性的类型、名称及其位置(position或offset )。 ●成员函数表(table of functions)──包括函数的类型、名称、及其参数类型等。 其目的是协助对象的I/O 和持久化(persistence) ﹐也提供调试讯息等。 ●能得知类所实例化的各对象 。 ●能参考到函数的源代码。 ●能取得类的有关在线说明(on-line documentation) 。 其实这些都是C++ 编译完成时﹐所丢弃的资料﹐如今只是希望寻找个途径来将之保留到执行期间。然而﹐要提供完整的RTTI﹐将会大幅提高C++ 的复杂度﹗ RTTI可能伴随的副作用 ion)方法﹐而不使用虚函数(virtual function)方法。 C++ 提供了RTTI﹐就可写个函数如下﹕ 当Figure类体系再派生出子类时﹐drawing() 函数的内容必须多加个if指令。因而违反 了「开放╱封闭原则」﹐如下﹕ 很显然地﹐drawing() 函数应加以修正。 系有个稳定的接口(interface) ﹐drawing() 使用这接口﹐使得drawing() 函数也稳定 ﹐不会随Figure类体系的扩充而变动。这是封闭的一面。而这稳定的接口并未限制Figure体系的成长﹐这是开放的一面。因而合乎「开放╱封闭」原则﹐软件的结构会更具弹性﹐更易于随环境而不断成长。 RTTI的常见的 类型(dynamic casting) 、模块集成、以及对象I/O 。 1.异常处理── 2.动态转类型── TI。 3.模块集成── 4.对象I/O ── 小对象﹐因之在存入数据库时﹐除了必须知道对象所属的类名称﹐也必须知道各内含小对象之所属类﹐才能完整地将对象存进去。储存时﹐也将这些RTTI资料连同对象内容一起存入数据库中。未来﹐读取对象时﹐可依据这些RTTI资料来分配内存空间给对象。 RTTI从那里来﹖ ●由类库提供RTTI──例如﹐Microsoft 公司的Visual C++环境。 ●由C++ 编译器(compiler)提供──例如﹐Borland C++ 4.5 版本。 ●由源代码产生器(code generator)提供──例如Bellvobr系统。 ●由OO数据库的特殊预处理器(preprocessor)提供──例如Poet系统。 ●由程序员自己加上去。 这些方法皆只提供简单的RTTI﹐其仅为Stroustrup先生所建议RTTI内涵的部分集合而已。相信不久的将来﹐会由C++ 编译器来提供ANSI标准的RTTI﹐但何时会订出这标准呢﹖没人晓得吧﹗ 程序员自己提供的RTTI |