【摘要】

       RTTI(Run-Time Type Identification)是面向对象程序设计中一种重要的技术。

现行的C++标准对RTTI已经有了明白的支持。

只是在某些情况下出于特殊的开发须要,我们须要自己编码来实现。本文介绍了一些关于RTTI的基础知识及其原理和实现,并分析比較三者是线上的差异与联系。

【正文】

RTTI 的需求

和非常多其它语言一样,C++是一种静态类型语言。其数据类型是在编译期就确定的,不能在执行时更改。然而因为面向对象程序设计中多态性的要求,C++中的指针或引用(Reference)本身的类型,可能与它实际代表(指向或引用)的类型并不一致。

有时我们须要将一个多态指针转换为事实上际指向对象的类型。就须要知道执行时的类型信息。这就产生了执行时类型识别的要求。

C++对RTTI的支持

C++提供了两个keywordtypeid和dynamic_cast,一个类type_info来支持RTTI。

  dynamic_cast操作符:它同意在执行时刻进行类型转换,从而使程序可以在一个类层次结构安全地转换类型。dynamic_cast提供了两种转换方式。把基类指针转换成派生类指针,或者把指向基类的左值转换成派生类的引用。

见下例讲述:

void company::payroll(employee *pe) {
//对指针转换失败,dynamic_cast返回NULL
if(programmer *pm=dynamic_cast(pe)){
pm->bonus();
}
} void company::payroll(employee &re) {
try{
//对引用转换失败的话,则会以抛出异常来报告错误
programmer &rm=dynamic_cast(re);
pm->bonus();
}
catch(std::bad_cast){
}
}

这里bonus是programmer的成员函数,基类employee不具备这个特性。

所以我们必须使用安全的由基类到派生类类型转换,识别出programmer指针。

 typeid操作符:它指出指针或引用指向的对象的实际派生类型。

比如:

employee* pe=new manager;
typeid(*pe)==typeid(manager) //true

typeid能够用于作用于各种类型名,对象和内置基本数据类型的实例、指针或者引用,当作用于指针和引用将返回它实际指向对象的类型信息。typeid的返回是type_info类型。

type_info类:这个类的确切定义是与编译器实现相关的。以下是《C++ Primer》中给出的定义(參考资料[2]中谈到编译器必须提供的最小信息量):

class type_info {
private:
type_info(const type_info&);
type_info& operator=( const type_info& );
public:
virtual ~type_info();
int operator==( const type_info& ) const;
int operator!=( const type_info& ) const;
const char* name() const;
};

详见:http://bbs.csdn.net/topics/40414128

三者比較:

宏能够在编译前用字符替换的办法展开,减轻程序猿反复编码的工作量。

c++的范型(模版)也是在编译时确定终于的程序样式。他用的办法是编译时确定类型信息。



RTTI是执行期类型信息,能够在执行时得到对象的类型信息。



我们考察一个程序,为了说明问题,我特意找了一个简单的程序,这个程序比較a和b,假设a大于b就交换他们。可是。a、b的类型并不确定可能是字符串也可能是整数还可能是复数。为了简洁和不至于造成过的混淆,我不使用操作符重载。假定不论什么操作都是基于对象方法的,为了完毕这个函数。a、b必须支持compare(比較)和swape(交换)方法。



我们不清楚a、b的类型,假设有3种类型我们就必须写3个函数吗?那太累人了。我们用来定义这个函数好了。

#define exchange(a,b) if(a.compare(b))a.swape(b);

这样我们在使用的时候就能够直接使用exchange宏来表达这个函数,并且能够适应各种类型,仅仅要他们都支持这两个函数就能够。

我们还能够用范型来实现这个函数

template<typename T>

void exchange(T &a, T &b)

{

  if(a.compare(b))a.swape(b)

}

我们相同达到了目的。



假设编译器支持丰富的RTTI,我们还能够用脚本语言的方式来实现他们。

exchange(a, b)

{

  if(a.compare(b))a.swape(b);

}



上面三种方式区别在哪里呢?

第一种。使用字符替换的方式,在编译前展开宏,使之成为程序中的一段代码。

另外一种,在编译时。确定调用函数的參数的类型,并自己主动生成一个这个类型的暂时函数。

第三种。在执行时依据參数的类型确定是否可以执行这段程序。

前2种都是在编译时确认的。第三种是在执行时确定的。

在程序设计中有着大量的反复代码,我们须要一种方法来提高效率,可是为什么看着结构类似的程序须要反复代码呢?最重要的原因是,传统的程序中实体(函数、变量、属性等等)在编译时都须要内存中一块确定的地址(或者相对基址的偏移)来指代。这时cpu处理方式的内在要求,而这个和程序设计时依照名字引用的思维习惯是不一致的。

我们能够用宏和模版来取代手工对每一个类型的特化,可是在程序中仍然是使用地址来指代实体的。实际上每一个类型的特化程序依旧存在,仅仅是在程序设计外观上不可见了。

第三种方式。使用RTTI。程序中的实体都不再是确定的地址来指代,而是通过字符串名称(或者实体表)来指代,在执行时依据名称来特化。这样的方法和前2个方法是本质的不同。

使用RTTI能够在非常大程度上减轻宏和静态模版带来的副作用,使程序具有更加优雅的外观。

可是。C++的宏和静态模版也不是一无是处。他用在对效率更加严格场合是很合适的。

C++ 宏、范型和RTTI 浅析的更多相关文章

  1. c++对象模型和RTTI(runtime type information)

    在前面已经探讨过了虚继承对类的大小的影响,这次来加上虚函数和虚继承对类的大小的影响. 先来回顾一下之前例子的代码: #include <iostream> using namespace ...

  2. RTTI(Runtime Type Information )

    RTTI 是“Runtime Type Information”的缩写,意思是:运行时类型信息.它提供了运行时确定对象类型的方法.本文将简略介绍 RTTI 的一些背景知识.描述 RTTI 的概念,并通 ...

  3. 微信终端开发团队:新年新语言,WCDB Swift

    欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者:sanhuazhang,此文发布在微信终端开发团队的专栏 WCDB 作为微信的终端数据库,从 2017.6 开源至今,共迭代了 5 个版本 ...

  4. 驳2B文 "我为什么放弃Go语言"

      此篇文章流传甚广, 其实里面没啥干货, 而且里面很多观点是有问题的. 这个文章在 golang-china 很早就讨论过了. 最近因为 Rust 1.0 和 1.1 的发布, 导致这个文章又出来毒 ...

  5. npm Scripts使用教程【译】

    Why npm Scripts? 原文发表于 2016.2.12,原文地址: https://css-tricks.com/why-npm-scripts/ 以下是访客Damon Bauer发布的一篇 ...

  6. 如何系统地自学一门Python 语言(转)

    转自:http://www.phpxs.com/post/4521 零基础情况下,学一门语言充实下自己,Python,简洁.优美.容易使用,是一个很好的选择.那么如何系统地自学Python呢? 有的人 ...

  7. C++实现反射机制

    NET下的很多技术都是基于反射机制来实现的,反射让.NET平台下的语言变得得心应手.最简单的,比如枚举类型,我们我可以很容易的获得一个枚举变量的数值以及其名称字符串. 可是,在C++中,枚举变量本质上 ...

  8. 【转载】如何系统地自学 Python?

    原文:如何系统地自学 Python? 作者:彭猫 本文由 知乎 彭猫 授权发布,版权所有归作者,转载请联系作者! 是否非常想学好 Python,一方面被琐事纠缠,一直没能动手,另一方面,担心学习成本太 ...

  9. 你真的精通Java吗?

    简历和自我介绍上经常能够读到“精通Java”这样的话,有人和我说,精通Java的人太多了,精通Java已经不能算亮点.不能给自己加分了.可是事实真是这样吗? 对于语言的学习,我有一种观点,一是纵向,即 ...

随机推荐

  1. 如何优雅的写UI——(5)选项卡功能实现

    先在我们的选项卡可以说能用了,每个标签页都能点进去,但是这还远远没到能用的地步,比如说你把窗口最大化后. 立马就露出马脚了,所以这篇我们要先讲讲tabctrl的最基本的功能实现 改变选项卡大小 上图的 ...

  2. nyist oj 1058 部分和问题 (DFS搜索)

    部分和问题 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描写叙述 给定整数a1.a2........an.推断能否够从中选出若干数,使它们的和恰好为K. 输入 首先,n和k ...

  3. 关于client浏览器界面文字内容溢出用省略号表示方法

    在实际的项目中,因为client浏览器文字内容的长度不确定性和页面布局的固定性,难免会出现文字内容超过div(或其它标签,下同)区域的情况.此时比較好的做法就是当文字超过限定的div宽度后自己主动以省 ...

  4. Go语言核心之美 1.5-作用域

    变量的作用域是指程序代码中能够有效使用这个变量的范围. 不要将作用域和生命期混在一起. 作用域是代码中的一块区域,是一个编译期的属性:生命期是程序执行期间变量存活的时间段.在此时间段内,变量能够被程序 ...

  5. UML绘图总结

    九种图总算画完了,着实让自己纠结了老一阵子啊. 只是,幸运的是完毕了,尽管还有些不足之处,可是终于战胜它了.以下说一下自己的绘图过程  一.用例图 UML的第一幅图应该说是用例图了,这是我们绘图的前提 ...

  6. js12--块作用域函数作用域

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...

  7. ubuntu-smb共享文件创建

    如何在计算机上实现资源共享                         --在本地用户目录下,创建一个smb文件夹                         --右击,选择share opt ...

  8. 28.semaphore跨进程通信

    根据id创建Semaphore,并初始化有一个信号量可用 name类型是char *...; HANDLE hsem = CreateSemaphoreA(NULL, 1, , name); 关闭句柄 ...

  9. C# Find() 与 FindAll()方法的使用

    Find()   :检索与指定匹配的第一个元素 FindAll()   : 检索与指定匹配的所有元素 如:List<string> strList=new List<string&g ...

  10. react+react-router+mobx+element打造管理后台系统---react-amdin-element

    react-admin-element,一款基于react的后台管理系统. 那么我们和其他的后台管理系统有什么区别呢? demo地址:点我进入demo演示 github地址:点我进入github 1. ...