通过运行时类型识别(RTTI),程序能够使用基类的指针或引用来检索这些指针或引用所指对象的实际派生类型。

通过下面两个操作符提供 RTTI:

1. typeid 操作符,返回指针或引用所指对象的实际类型。

2. dynamic_cast 操作符,将基类类型的指针或引用安全地转换为派生类型的指针或引用。

注意,这些操作符只为带有一个或多个虚函数的类返回动态类型信息,对于其他类型,返回静态(即编译时)类型的信息。对于带虚函数的类,在运行时执行 RTTI 操作符,但对于其他类型,在编译时计算 RTTI 操作符。

1:dynamic_cast 操作符

可以使用 dynamic_cast 操作符将基类类型对象的引用或指针转换为同一继承层次中其他类型的引用或指针。与 dynamic_cast 一起使用的指针必须是有效的——它必须为 0 或者指向一个对象。

dynamic_cast 涉及运行时类型检查。如果绑定到引用或指针的对象不是目标类型的对象,则 dynamic_cast 失败。如果转换到指针类型的 dynamic_cast 失败,则 dynamic_cast 的结果是 0 值;如果转换到引用类型的 dynamic_cast 失败,则抛出一个 bad_cast 类型的异常。

可以对值为 0 的指针应用 dynamic_cast,这样做的结果是 0。

假定 Base 是至少带一个虚函数的类,并且 Derived 类派生于Base 类。如果有一个名为 basePtr 的指向 Base 的指针,就可以像这样在运行时将它强制转换为指向 Derived 的指针:

if (Derived *derivedPtr = dynamic_cast<Derived*>(basePtr))
{
// use the Derived object to which derivedPtr points
} else { // BasePtr points at a Base object
// use the Base object to which basePtr points
}

也可以使用 dynamic_cast 将基类引用转换为派生类引用,这种 dynamic_cast 操作的形式如下: dynamic_cast< Type& >(val)

只有当 val 实际引用一个 Type 类型对象,或者 val 是一个 Type 派生类型的对象的时候,dynamic_cast 操作才将操作数 val 转换为想要的 Type& 类型。当转换失败的时候,它抛出一个 std::bad_cast 异常,该异常在库头文件 typeinfo 中定义。

重写前面的例子如下:

void f(const Base &b)
{
try {
const Derived &d = dynamic_cast<const Derived&>(b);
// use the Derived object to which b referred
} catch (bad_cast) {
// handle the fact that the cast failed
}
}

2:typeid 操作符

typeid 操作符使程序能够返回一个表达式的类型。typeid 表达式形如:typeid(e) 。这里 e 是任意表达式或者是类型名。

typeid 操作符的结果是名为 type_info 的标准库类型的对象引用。

如果表达式的类型是类类型且该类包含一个或多个虚函数,则表达式的动态类型可能不同于它的静态编译时类型。例如,如果表达式对基类指针解引用,则该表达式的静态编译时类型是基类类型;但是,如果指针实际指向派生类对象,则 typeid 操作符将说表达式的类型是派生类型。

typeid 操作符可以与任何类型的表达式一起使用。内置类型的表达式以及常量都可以用作 typeid 操作符的操作数。如果操作数不是类类型或者是没有虚函数的类,则 typeid 操作符指出操作数的静态类型;如果操作数是定义了至少一个虚函数的类类型,则在运行时计算类型。

typeid 最常见的用途是比较两个表达式的类型,或者将表达式的类型与特定类型相比较:

Base *bp;
Derived *dp;
if (typeid(*bp) == typeid(*dp)) {
// bp and dp point to objects of the same type
}
if (typeid(*bp) == typeid(Derived)) {
// bp actually points to a Derived
}

注意,typeid 的操作数是表示对象的表达式——测试 *bp,而不是 bp。

如果指针 p 的值是 0,那么,如果 p 的类型是带虚函数的类型,则typeid(*p) 抛出一个 bad_typeid 异常;如果 p 的类型没有定义任何虚函数,则结果与 p 的值是不相关的。正像计算表达式 sizeof一样,编译器不计算 *p,它使用 p 的静态类型,这并不要求 p 本身是有效指针。

3:type_info 类

type_info 类的确切定义随编译器而变化,但是,标准保证所有的实现将至少提供下表 列出的操作。

t1 == t2

如果两个对象 t1 和 t2 类型相同,就返回 true;否则,返回false

t1 != t2

如果两个对象 t1 和 t2 类型不同,就返回 true;否则,返回false

t.name()

返回 C 风格字符串,这是类型名字的可显示版本。类型名字用系统相关的方法产生

t1.before(t2)

返回指出 t1 是否出现在 t2 之前的 bool 值。before 强制的次序与编译器有关

默认构造函数和复制构造函数以及赋值操作符都定义为 private,所以不能定义或复制 type_info 类型的对象。程序中创建 type_info 对象的唯一方法是使用 typeid 操作符。

name 函数为 type_info 对象所表示的类型的名字返回 C 风格字符串。给定类型所用的值取决于编译器:

int iobj;
cout << typeid(iobj).name() << endl
<< typeid(8.16).name() << endl
<< typeid(std::string).name() << endl
<< typeid(Base).name() << endl
<< typeid(Derived).name() << endl;

name 返回的格式和值随编译器而变化。在我们的机器上执行时,这个程序产生下面的输出:

i
d
Ss
4Base
7Derived

C++运行时类型识别的更多相关文章

  1. RTTI 运行时类型识别 及异常处理

    RTTI   运行时类型识别 typeid  ------  dynamic_cast dynamic_cast 注意事项: 1.只能应用于指针和引用之间的转化 2.要转换的类型中必须包含虚函数 3. ...

  2. RTTI (Run-Time Type Identification,通过运行时类型识别) 转

    参考一: RTTI(Run-Time Type Identification,通过运行时类型识别)程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型.   RTTI提供了以下两个 ...

  3. MFC六大核心机制之二:运行时类型识别(RTTI)

    上一节讲的是MFC六大核心机制之一:MFC程序的初始化,本节继续讲解MFC六大核心机制之二:运行时类型识别(RTTI). typeid运算子 运行时类型识别(RTTI)即是程序执行过程中知道某个对象属 ...

  4. c++运行时类型识别(rtti)

    一个简单运行时类型识别 namespace rtti_ex { /* * 类型信息基类 */ class i_type_info { public: // 判断是否是指定类型 bool is(cons ...

  5. Java基础之RTTI 运行时类型识别

    运行时类型识别(RTTI, Run-Time Type Identification)是Java中非常有用的机制,在Java运行时,RTTI维护类的相关信息. 多态(polymorphism)是基于R ...

  6. 框架原理第二讲,RTTI,运行时类型识别.(以MFC框架讲解)

    框架原理第二讲,RTTI,运行时类型识别.(以MFC框架讲解) 一丶什么是RTTI,以及RTTI怎么设计 通过第一讲,我们知道了怎么样升成一个窗口了,以及简单的消息循环. 第二讲则是主要讲解RTTI ...

  7. MFC原理第三讲.RTTI运行时类型识别

    MFC原理第三讲.RTTI运行时类型识别 一丶什么是RTTI RTTI. 运行时的时候类型的识别. 运行时类型信息程序.能够使用基类(父类)指针 或者引用 来检查这些指针或者引用所指的对象. 实际派生 ...

  8. (C/C++学习笔记) 二十三. 运行时类型识别

    二十三. 运行时类型识别 ● 定义 运行时类型识别(Run-time Type Identification, RTTI) 通过RTTI, 程序能够使用基类的指针或引用来检查(check)这些指针或引 ...

  9. RTTI(运行时类型识别)

    运行时类型识别(Run-time type identification , RTTI),是指在只有一个指向基类的指针或引用时,确定所指对象的准确类型的操作.其常被说成是C++的四大扩展之一(其他三个 ...

  10. 《深入浅出MFC》系列之运行时类型识别(RTTI)

    /********************************************************************************** 发布日期:2017-11-13  ...

随机推荐

  1. a标签实现 批量下载

    // 批量下载 download (name, href) { var a = document.createElement('a') var e = document.createEvent('Mo ...

  2. windows远程连接linux-安装xfce界面,ubuntn添加新用户

    参考:“ 使用xrdp实现windows 远程桌面连接linux”   http://blog.csdn.net/qq_33530388/article/details/64502902; http: ...

  3. Visual Studio 2019 正式发布

    原文链接: https://www.oschina.net/news/105629/vs2019-general-availability 如约而至,微软已于今天推出 Visual Studio 20 ...

  4. H5C3--background中cover,背景样式,提升响应区域+精灵图的使用

    一.cover的使用 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...

  5. Objective-C头文件导出工具class-dump

    首先,这个工具是开源的.作者网站:http://stevenygard.com/projects/class-dump/ 用途: 分析库文件或可执行文件,得到Objective-C类和部分C结构体的信 ...

  6. Intent 传递Map数据

    android开发默认情况下,通过Bundle bundle=new Bundle();传递值是不能直接传递map对象的,解决办法: 第一步:封装自己的map,实现序列化即可 /** *序列化map供 ...

  7. 洛谷P1311 [NOIP2011提高组Day1T2]选择客栈

    P1311 选择客栈 题目描述 丽江河边有n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号.每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示),且每家客栈都设有一 ...

  8. 【洛谷P1204】【USACO1.2】挤牛奶Milking Cows

    P1204 [USACO1.2]挤牛奶Milking Cows 题目描述 三个农民每天清晨5点起床,然后去牛棚给3头牛挤奶.第一个农民在300秒(从5点开始计时)给他的牛挤奶,一直到1000秒.第二个 ...

  9. phpstorm服务器配置

    转载自百度经验https://jingyan.baidu.com/article/84b4f565ea229960f6da320c.html 这个教程里面后面修改的两步目前没有用到,之后可能会用到,暂 ...

  10. Mac上的包管理器Homebrew的介绍及安装和使用实践

    Homebrew的作用 Homebrew是OS X上强大的包管理器,为系统软件提供了非常方便的安装方式,独特式的解决了包的依赖问题,并不再需要烦人的sudo,一键式编译,无参数困扰. 如何安装Home ...