通过运行时类型识别(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. PHP生成linux命令行进度条

    <?php$total = 100; for ($i = 1; $i <= $total; $i++) { printf("progress: [%-50s] %d%% Done ...

  2. webstorm之Monokai-Sublime主题颜色设置方法及激活注册码

    打开https://github.com/OtaK/jetbrains-monokai-sublime 链接,然后点击右边的下载ZIP文件即可.解压之后,会得到一个Monokai-Sublime.ja ...

  3. memcache缓存使用详解

    初始化一个Memcache的对象:$mem = new Memcache(); 连接到我们的Memcache服务器端,第一个参数是服务器的IP地址,也可以是主机名,第二个参数是Memcache的开放的 ...

  4. 常用命令4-文件搜索命令 2- which

    大家发现,cd 使用whereis和使用which都找不到他所在位置.是因为cd是linux的shell内置命令.那什么是shell,就是当前咱们操作界面.咱们看到的ls等命令都是通过外部安装的,所以 ...

  5. java-异常处理1

    概要图 异常讲解流程图 一 java 异常和错误层次图 1.1 图1 1.2 图2 二 异常生的过程 1 异常可以结束函数. 同时也让程序结束了. 三 异常和错误的发生和区别 Java运行时期发生的问 ...

  6. tcpdump命令介绍

    命令格式为:tcpdump [-nn] [-i 接口] [-w 储存档名] [-c 次数] [-Ae] [-qX] [-r 文件] [所欲捕获的数据内容] 参数: -nn,直接以 IP 及 Port ...

  7. PHP--y2k38的解决方法已经时间格式的常用转换

    y2k38又名千年虫问题,又称Uinx Millennium Bug,此漏洞将会影响到所有32位系统下用Unix时间戳整数来记录时间的PHP,及其它编程语言. 一个整型的变量所能保存的最大时间为203 ...

  8. ajax下载小于500M大文件【原】

    不推荐使用的FileReader 之前用FileReader读取下载文件,当文件超过1M浏览器就立即扑街了 // 文件下载 function download(blob, fileName) { va ...

  9. NFS客户端挂载目录后无写入权限的解决方案

    转载至:https://blog.csdn.net/younger_china/article/details/52089337 在客户机通过 mount -o rw -t nfs 192.168.1 ...

  10. 一个不错的插件(软件).NET开发

    http://www.gcpowertools.com.cn/products/default.htm 葡萄城 先记录一下!