C++运行时类型识别
通过运行时类型识别(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++运行时类型识别的更多相关文章
- RTTI 运行时类型识别 及异常处理
RTTI 运行时类型识别 typeid ------ dynamic_cast dynamic_cast 注意事项: 1.只能应用于指针和引用之间的转化 2.要转换的类型中必须包含虚函数 3. ...
- RTTI (Run-Time Type Identification,通过运行时类型识别) 转
参考一: RTTI(Run-Time Type Identification,通过运行时类型识别)程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型. RTTI提供了以下两个 ...
- MFC六大核心机制之二:运行时类型识别(RTTI)
上一节讲的是MFC六大核心机制之一:MFC程序的初始化,本节继续讲解MFC六大核心机制之二:运行时类型识别(RTTI). typeid运算子 运行时类型识别(RTTI)即是程序执行过程中知道某个对象属 ...
- c++运行时类型识别(rtti)
一个简单运行时类型识别 namespace rtti_ex { /* * 类型信息基类 */ class i_type_info { public: // 判断是否是指定类型 bool is(cons ...
- Java基础之RTTI 运行时类型识别
运行时类型识别(RTTI, Run-Time Type Identification)是Java中非常有用的机制,在Java运行时,RTTI维护类的相关信息. 多态(polymorphism)是基于R ...
- 框架原理第二讲,RTTI,运行时类型识别.(以MFC框架讲解)
框架原理第二讲,RTTI,运行时类型识别.(以MFC框架讲解) 一丶什么是RTTI,以及RTTI怎么设计 通过第一讲,我们知道了怎么样升成一个窗口了,以及简单的消息循环. 第二讲则是主要讲解RTTI ...
- MFC原理第三讲.RTTI运行时类型识别
MFC原理第三讲.RTTI运行时类型识别 一丶什么是RTTI RTTI. 运行时的时候类型的识别. 运行时类型信息程序.能够使用基类(父类)指针 或者引用 来检查这些指针或者引用所指的对象. 实际派生 ...
- (C/C++学习笔记) 二十三. 运行时类型识别
二十三. 运行时类型识别 ● 定义 运行时类型识别(Run-time Type Identification, RTTI) 通过RTTI, 程序能够使用基类的指针或引用来检查(check)这些指针或引 ...
- RTTI(运行时类型识别)
运行时类型识别(Run-time type identification , RTTI),是指在只有一个指向基类的指针或引用时,确定所指对象的准确类型的操作.其常被说成是C++的四大扩展之一(其他三个 ...
- 《深入浅出MFC》系列之运行时类型识别(RTTI)
/********************************************************************************** 发布日期:2017-11-13 ...
随机推荐
- UVA10215The Largest/Smallest Box(小数精度)
本身很容易却因为评测机有毒的一道题,,,看网上题解说最后一个答案要加一个很小的数才能AC,据说是因为没有speci judge #include <iostream> #include & ...
- Highcharts 饼图数值显示在图形上
1.引用js文件 <script type="text/javascript" src="http://cdn.hcharts.cn/jquery/jquery-1 ...
- ES6学习笔记之Symbol
新的数据类型Symbol 1. 概述 ES5 的对象属性名都是字符串,这容易造成属性名的冲突.比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与 ...
- 弹性盒布局(flex)
一.Flex 布局是什么? Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性. 任何一个容器都可以指定为 Flex 布局. .box ...
- proteus 8.8 直装版提示Symbol $MKRORIGIN used but not found in libraries 安装后没有库
用管理员运行程序,然后再通过菜单打开仿真文件是没问题. 解决方法:通常的安装目录是C:\Program Files (x86)\Labcenter Electronics\Proteus 8 Prof ...
- 模板方法(Template Method)(父类声明算法骨架,子类具体不同实现)
在阎宏博士的<JAVA与模式>一书中开头是这样描述模板方法(Template Method)模式的: 模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式 ...
- rabbitmq启用和禁用web界面管理插件
rabbitmq默认安装启动以后,是没有开启web管理界面的,通过rabbitmq-plugins list命令可列出插件的启用和禁用状态. 使用rabbitmq-plugins enable xxx ...
- python 变量离散化
- Centos无法连接无线网络解决办法
系统->管理->服务器设置->服务,将NetworkManager选项勾选,点击重启服务.然后就可以看到右上角已经有了网络连接.
- Flask – SQLAlchemy成员增加
目录 简介 结构 展示 技术 运行 代码 创建数据库表单 views视图 home主页 添加成员addnew.html 展示页show_all 简介 结构 $ tree -I "__pyca ...