RTTI和类型转换

C++ RTTI和类型转换运算符 目录 一、RTTI 1、dynamic_cast运算符 2、dynamic_cast实现原理 3、typeid 运算符和type_info类 4、typeid 实现原理 二、类型转换运算符 1、static_cast 运算符 2、const_cast 3、reinterpret_cast 一、RTTI RTTI是Runtime Type Identific... 阅读详情
RTTI
通过运行时类型识别(RTTI),程序能够使用基类的指针或引用来检索这些指针或引用所指对象的实际派生类型。通过下面两个操作符提供 RTTI:
1. typeid 操作符,返回指针或引用所指对象的实际类型。
2. dynamic_cast 操作符,将基类类型的指针或引用安全地转换为派生类型的指针或引用。
这些操作符只为带有一个或多个虚函数的类返回动态类型信息,对于其他类型,返回静态(即编译时)类型的信息。对于带虚函数的类,在运行时执行 RTTI 操作符,但对于其他类型,在编译
时计算 RTTI 操作符。
当具有基类的引用或指针,但需要执行不是基类组成部分的派生类操作的时候,需要动态的强制类型转换。通常,从基类指针获得派生类行为最好的方法是通过虚函数。当使用虚函数的时候,编译器自动根据对象的实际类型选择正确的函数。但是,在某些情况下,不可能使用虚函数。在这些情况下,RTTI 提供了可选的机制。然而,这种机制比使用虚函数更容易出错:程序员必须知道应该将对象强制转换为哪种类型,并且必须检查转换是否成功执行了。
使用动态强制类型转换要小心。只要有可能,定义和使用虚函数比直接接管类型管理好得多。

dynamic_cast
将基类类型对象的引用或指针转换为同一继承层次中其他类型的引用或指针。注:传入dynamic_cast的参数对应的类,必须带有virtual函数,否则,编译无法通过。dynamic_cast 涉及运行时类型检查。如果绑定到引用或指针的对象不是目标类型的对象,则 dynamic_cast 失败。如果转换到指针类型的 dynamic_cast 失败,则 dynamic_cast 的结果是 0 值;如果转换到引用类型的 dynamic_cast 失败,则抛出一个 bad_cast 类型的异常。

typeid 操作符
typeid 表达式形如:typeid(e);这里 e 是任意表达式或者是类型名。如果表达式的类型是类类型且该类包含一个或多个虚函数,则表达式的动态类型可能不同于它的静态编译时类型;
typeid 操作符可以与任何类型的表达式一起使用。内置类型的表达式以及常量都可以用作 typeid 操作符的操作数。如果操作数不是类类型或者是没有虚函数的类,则 typeid 操作符指出操作数的静态类型;如果操作数是定义了至少一个虚函数的类类型,则在运行时计算类型。

typeid 操作符的结果是名为 type_info 的标准库类型的对象引用,要使用 type_info 类,必须包含库头文件typeinfo。
typeid 最常见的用途是比较两个表达式的类型,或者将表达式的类型与特定类型相比较:只有当 typeid 的操作数是带虚函数的类类型的对象的时候,才返回动态类型信息。测试指针(相对于指针指向的对象)返回指针的静态的、编译时类型。如果指针 p 的值是 0,那么,如果 p 的类型是带虚函数的类型,则typeid(*p) 抛出一个 bad_typeid 异常;如果 p 的类型没有定义任何虚函数,则结果与 p 的值是不相关的。正像计算表达式 sizeof一样,编译器不计算 *p,它使用 p 的静态类型,这并不要求 p 本身是有效指针。

实例
#include <iostream>
#include <typeinfo>

using namespace std;

class Base
{
     public:
          virtual void func(){cout << "I, Base." << endl;}
};

class Derived:public Base
{
     public:
          void dfunc(){cout << "I, Derived." << endl;}
};

class BadDerived
{
     public:
          virtual void func(){cout << "I, BadDerived." << endl;}
};
class T
{
     public:
          void dfunc(){cout << "I, T." << endl;}
};
int main()
{
     Base *baseptr = new Derived;
     BadDerived *badptr = new BadDerived;

     cout << endl << "*********Test 0************" << endl;
     if(T *deriveptr = dynamic_cast<T*>(baseptr))
     {
          cout << "success---->";
          deriveptr->dfunc();
     }
     else
     {
          cout << "failed----->";
          baseptr->func();
          cout << "DEBUG" << endl;
          cout << "typeid(T).name = " << typeid(T).name() << endl;
          cout << "typeid(Baseref).name = " << typeid(*baseptr).name() << endl;
     }
     cout << endl << "*********Test 1************" << endl;
     if(Derived *deriveptr = dynamic_cast<Derived*>(baseptr))
     {
          cout << "success---->";
          deriveptr->dfunc();
     }
     else
     {
          cout << "failed----->";
          baseptr->func();
          cout << "DEBUG" << endl;
          cout << "typeid(Derived).name = " << typeid(Derived).name() << endl;
          cout << "typeid(Baseref).name = " << typeid(*baseptr).name() << endl;
     }
     cout << endl << "*********Test 2************" << endl;
     if(Derived *deriveptr = dynamic_cast<Derived*>(badptr))
     {
          cout << "success---->";
          deriveptr->dfunc();
     }
     else                            
     {                               
          cout << "failed----->";
          badptr->func();
          cout << "DEBUG" << endl;
          cout << "typeid(Derived).name = " << typeid(Derived).name() << endl;
          cout << "typeid(Baseref).name = " << typeid(*badptr).name() << endl;
     }

     Derived deriveobj;
     Base &baseref = deriveobj;
     BadDerived badobj;
     BadDerived &badref = badobj;

     cout << endl << "*********Test 3************" << endl;
     try
     {
          Derived &deriveref = dynamic_cast<Derived&>(baseref);
          cout << "success---->";
          deriveref.dfunc();
     }
     catch(bad_cast)
     {
          cout << "failed----->";
          baseref.func();
          cout << "DEBUG" << endl;
          cout << "typeid(Derived).name = " << typeid(Derived).name() << endl;
          cout << "typeid(Baseref).name = " << typeid(baseref).name() << endl;
     }
     cout << endl << "*********Test 4************" << endl;
     try
     {
          Derived &deriveref = dynamic_cast<Derived&>(badref);
          cout << "success---->";
          deriveref.dfunc();
     }
     catch(bad_cast)
     {
          cout << "failed----->";
          baseref.func();
          cout << "DEBUG" << endl;
          cout << "typeid(Derived).name = " << typeid(Derived).name() << endl;
          cout << "typeid(Baseref).name = " << typeid(badref).name() << endl;
     }
     cout << endl << "*********Test 5************" << endl;
     if(typeid(Derived) == typeid(baseref))
     {
          Derived &deriveref = dynamic_cast<Derived&>(baseref);
          cout << "success---->";
          deriveref.dfunc();
     }
     else
     {
          cout << "failed----->";
          baseref.func();
          cout << "DEBUG" << endl;
          cout << "typeid(Derived).name = " << typeid(Derived).name() << endl;
          cout << "typeid(Baseref).name = " << typeid(baseref).name() << endl;
     }
     cout << endl << "*********Test 6************" << endl;
     if(typeid(Derived) == typeid(badref))
     {
          Derived &deriveref = dynamic_cast<Derived&>(badref);
          cout << "success---->";
          deriveref.dfunc();
     }
     else
     {
          cout << "failed----->";
          badref.func();
          cout << "DEBUG" << endl;
          cout << "typeid(Derived).name = " << typeid(Derived).name() << endl;
          cout << "typeid(Baseref).name = " << typeid(badref).name() << endl;
     }
}

执行结果
*********Test 0************
failed----->I, Base.
DEBUG
typeid(T).name = 1T
typeid(Baseref).name = 7Derived

*********Test 1************
success---->I, Derived.

*********Test 2************
failed----->I, BadDerived.
DEBUG
typeid(Derived).name = 7Derived
typeid(Baseref).name = 10BadDerived

*********Test 3************
success---->I, Derived.

*********Test 4************
failed----->I, Base.
DEBUG
typeid(Derived).name = 7Derived
typeid(Baseref).name = 10BadDerived

*********Test 5************
success---->I, Derived.

*********Test 6************
failed----->I, BadDerived.
DEBUG
typeid(Derived).name = 7Derived
typeid(Baseref).name = 10BadDerived

类型转换

C风格转换是“万能的转换”,但需要程序员把握转换的安全性,编译器无能为力。

类型转换的不安全来源于两个方面:其一是类型的窄化转化,会导致数据位数的丢失;其二是在类继承链中,将父类对象的地址(指针)强制转化成子类的地址(指针),这就是所谓的下行转换,“下”表示沿着继承链向下走(向子类的方向走)。类似地,上行转换的“上”表示沿继承链向上走(向父类的方向走);上行转换一般是安全的,下行转换很可能是不安全的;因为子类中包含父类,所以上行转换(只能调用父类的方法,引用父类的成员变量)一般是安全的。但父类中却没有子类的任何信息,而下行转换会调用到子类的方法、引用子类的成员变量,这些父类都没有,所以很容易“指鹿为马”或者干脆指向不存在的内存空间。

static_cast <new_type> (expression) 静态转换

static_cast最接近于C风格转换,但在无关类指针转换时,编译器会报错,提升了安全性。

dynamic_cast <new_type> (expression) 动态转换

动态转换确保类指针的转换是合适完整的,它有两个重要的约束条件,其一是要求new_type为指针或引用,其二是下行转换时要求基类是多态的(基类中包含至少一个虚函数),如果发现下行转换不安全,dynamic_cast返回一个null指针。当待转换指针是void*或者转换目标指针是void*时,dynamic_cast总是认为是安全的。

reinterpret_cast <new_type> (expression) 重解释转换

这个转换是最“不安全”的,两个没有任何关系的类指针之间转换都可以用这个转换实现。reinterpret_cast可以把整型数转换成地址(指针),这种转换在系统底层的操作,有极强的平台依赖性,移植性不好;它同样要求new_type是指针或引用。

const_cast <new_type> (expression) 常量向非常量转换

const_cast可以将常量转成非常量,但不会破坏原常量的const属性,只是返回一个去掉const的变量。从char *cc = const_cast<char *>(c)可以看出了这个转换的作用了,但切记,这个转换并不转换原常量本身,即c还是常量,只是它返回的结果cc是非常量了。




深入理解C++操作符重载与内存管理 本文深入探讨了C++中的操作符重载,类型转换,新式类型转换和RTTI的相关知识,特别关注了new和delete操作符的重载以及继承对这些操作符的影响。通过对代码示例的分析,展示了如何正确重载操作符以及如何处理继承导致的问题。文章还介绍了下标操作符的重载,包括如何为非常量对象和常量对象实现不同的重载函数,并强调了常量函数返回值应为常量引用的重要性。 阅读详情

相关推荐

强类型系统 RTTI 类型识别

强类型系统RTTI,类型识别系统,对于像了解这个概念的同仁们,是不错的选择!

RTTI和类型转换运算符

RTTI和类型转换运算符

jianmo的博客 375

C# 进阶:打造WinForms中的动态交互式UserControl

本文深入探讨了如何在C# WinForms中创建动态交互式UserControl,以提升桌面应用的用户体验和代码复用性。通过剖析UserControl生命周期、事件体系,并结合一个可拖拽缩放的分割面板实战案例,详细讲解了鼠标键盘事件处理、自定义绘制、状态管理以及性能优化等核心技巧,帮助开发者封装复杂交互逻辑,打造专业级自定义控件。

weixin_29279153的博客 460

linux 类型转换,C++ 类型转换及RTTI

一、C++的4中类型转换我们应该比较熟悉C的类型转换即由圆括号和标识符组成,但是对于C的类型转换有时候到不到我们的要求,比如去除const 的类型转换,把一个指向基类的指针转化成指向子类的指针等等。下面就介绍C++引进的四个新的类型转换操作符,这四个操作符是:static_cast, const_cast, dynamic_cast, 和reinterpret_cast。1,const_cast ...

weixin_40006133的博客 379

AGM Supra软件从零到一:国产CPLD工程创建全流程实战解析

本文详细解析了AGM Supra软件在国产CPLD开发中的全流程实战操作,从工程创建到代码开发、编译调试,再到高级技巧与疑难排解。特别对比了Supra与Quartus的差异,提供了工程路径管理、Quartus项目转换、HDL代码规范等实用技巧,帮助开发者高效完成CPLD项目开发。

weixin_29193259的博客 501

EtherCAT丢包问题深度解析:从原理到实战排查指南

在工业自动化与运动控制领域,实时通讯网络的稳定性是系统可靠运行的基石。EtherCAT(以太网控制自动化技术)作为一种高性能工业以太网协议,其核心在于独特的“飞读飞写”机制和纳秒级的分布时钟同步,以实现多设备间的精准协同。然而,物理链路干扰、配置不当或硬件性能瓶颈都可能导致数据帧丢失,破坏时钟同步,进而引发伺服抖动、定位精度下降乃至生产线停机。本文聚焦于EtherCAT丢包这一典型故障,结合SSC(Slave Stack Code Tool)从站协议栈开发与实时系统调优等工程实践,系统阐述其成因、影响及一套

weixin_32050773的博客 341

RTTI的开启和关闭

我们使用dynamic_cast就是基于RTTI的,我们可以通过编译器对RTTI进行开启或者关闭,关闭之后dynamic_cast就无法使用。RTTI是运行时类型识别,C++引入这个机制是为了让程序在运行时能根据基类的指针或引用来获得该指针或引用所指的对象的实际类型。我们可以右击项目,然后选择属性->C/C++->语言->启用运行时类型信息,这样就可以开启或者关闭相应的RTTI了。而linux中可以以其它方式开启或者关闭,比如可以借助编译器的选项进行开启或者关闭,选项来关闭 RTTI。

weixin_68026222的博客 1046

别再手动量了!用Python+Open3D给BIM模型做‘CT扫描’,自动揪出施工误差(附完整代码)

本文介绍如何利用Python和Open3D技术实现BIM模型的毫米级施工误差自动检测。通过点云预处理、模型配准和偏差分析,系统能自动生成三维差异热力图和验收报告,显著提升施工质量检测效率。特别适合混凝土结构错位和钢结构安装偏差等常见问题的智能分析。

weixin_29284657的博客 243

C++ RTTI 和四种类型转换

RTTI 是 Run Time Type Information 的缩写,从字面上来理解就是执行时期的类型信息,其重要作用就是动态判别执行时期的类型。 并不是说这篇文章是RTTI,和用于RTTI的四种类型转换,而是介绍RTTI,再介绍一下4种类型转换,因为RTTI有用到其中一种类型转换,所以相当于两篇文章写在一起。 实际上 RTTI 用到的是typeid() 和 dynamic_cast()。 为什么会有RTTI? C++是一种静态类型语言,其数据类型是在编译期就确定的,不能在运行时更改。然而由于面向对象程

我放低了酒杯 528

PyTorch实战(4)——卷积神经网络(Convolutional Neural Network,CNN)

卷积神经网络 (Convolutional Neural Network, CNN) 是一种广泛应用的深度学习模型。通过参数共享、局部感知和空间结构等优势,能够更好地处理图像数据,并在图像识别、目标检测和图像生成等任务中展现出强大的能力。在本节中,介绍了卷积的计算方法以及卷积神经网络的基本组件,并使用 PyTorch 构建了卷积神经网络以深入了解其工作原理。

盼小辉丶的博客 1万+

【异常】安装OpenClaw遇到 Windows环境pnpm安装node-llama-cpp postinstall生命周期脚本执行失败完整解决方案

摘要: Windows环境下使用pnpm安装node-llama-cpp时,postinstall脚本执行失败(错误码3221225477),主要因缺少C++编译工具链或预构建二进制下载失败。解决方案: 基础排查:确保管理员权限、Node.js ≥18、路径无中文; 安装编译工具:推荐Visual Studio的“C++桌面开发”组件或windows-build-tools; 环境变量配置:强制CPU模式+国内镜像(NODE_LLAMA_CPP_FORCE_CPU=true,镜像地址替换为国内源); pnp

奶爸的编程之路,也就一周冷个三天 618

RTTI 和 类型转换运算符

RTTI(Runtime Type Identification),译为运行阶段类型识别。是新添加到C++的特性。 1、用途。 对于一个类层次结构:其中的类都是从一个基类派生而来,则可以让基类指针指向其中任何一个类的对象。 则可以调用函数:在处理一些信息后,选择一个类,并创建这种类型的对象,之后返回它的地址。 该地址可以被基类指针引用。然而,我们并不知道基类指针指向的是什么对象。 在回答这个问题前,先考虑为何要知道类型——若仅仅是希望调用类方法的正确版本,则只要该类层次结构中所有成员都拥有虚函数,

Ho_mu_ra的博客 291

地平线J6的基础简介

地平线J6M芯片:面向中阶辅助驾驶市场的高性价比芯片

weixin_43084908的博客 4446

C++类型转换和RTTI

C++中的自定义类型转换允许程序员定义自己的转换规则,以便在不同类型之间进行转换。①转换构造函数:转换构造函数允许将其它类型的数据转换为类类型。它只有一个参数,或者其它参数都有默认值。当遇到需要类型转换的情况时,编译器会自动调用转换构造函数完成隐式转换。②类型转换运算符:operator类型转换运算符允许将类类型转换为其它类型。它没有参数和返回值,且必须被定义为成员函数。语法:operator关键字加要转换的目标类型。

2301_82023822的博客 986

【EDA Tools】Spyglass 检查 Verilog 和 SystemVerilog 混合语言及 Lint 检查

Spyglass可以用于检查混合设计中的语言互操作性和一致性问题。对于设计中包含多种硬件描述语言的情况,Spyglass 能够识别并解析其中的模块及其互连,并对其进行验证。例如,在包含 Verilog 和 VHDL 的混合设计中,Spyglass 会自动识别并解析 Verilog 和 VHDL 文件及其相互连接。通过运行 Spyglass Lint 功能,可以检查混合设计中的语言一致性问题,例如不兼容的数据类型、互操作性问题以及其他可能导致设计故障或不一致的问题。

记录学习历程 5078

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

C++复习补充 类型转换和RTTI

类型转换 类与类之间的类型转换 四种显示类型转换 类型转换注意事项 RTTI

Yusei_0523的博客 458

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

C++ 四个强制类型转换符和RTTI

1.新增的四个强制类型转换符 “强制”的含义:在告诉编译器: “我知道你不愿意这样做,可是你必须做,尽管执行吧,后果由我负责!” const_cast除去对象的常属性。转换的是表达式而非自身. 形式:const_cast ( object ) static_cast用来进

whz_zb的专栏 2072

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

c++的RTTI和类型转换操作符

...

https://gitee.com/liuyuan185442111/chest-view 852

DELPHI中使用RTTI

    运行期类型信息(RTTI)是一种语言特征,能使应用程序在运行时得到关于对象的信息。RTTI是Delphi的组件能够融合到IDE中的关键。它在IDE中不仅仅是一个纯学术的过程。    由于对象都是从TObject继承下来的,因此,对象都包含一个指向它们的RTTI的指针以及几个内建的方法。下面的表列出了TObject的一些方法,用这些方法能获得某个对象实例的信息。

1212

【C++】类型转换

使用dynamic_cast进行向下转型则是安全的,如果父类的指针(或引用)指向的是子类对象那么dynamic_cast会转换成功,但如果父类的指针(或引用)指向的是父类对象那么dynamic_cast会转换失败并返回一个空指针。上述代码中,如果传入func函数的是子类对象的地址,那么在转换后pb1和pb2都会有对应的地址,但如果传入func函数的是父类对象的地址,那么转换后pb1会有对应的地址,而pb2则是一个空指针。dynamic_cast用于将父类的指针(或引用)转换成子类的指针(或引用)。

m0_70088010的博客 1106

类型转换与RTTI

一、类型转换1、C语言2、C++3、注意二、static_cast1、介绍2、示例三、reinterpret_cast1、介绍2、示例代码3、运行结果四、const_cast1、介绍2、示例五、dynamic_cast1、介绍2、示例代码3、运行结果六、RTTI1、介绍2、typeid(1)介绍(2)示例代码3、decltype

Snow_Dragon_L的博客 684

【C++】友元、嵌套类、异常、RTTI、类型转换运算符

友元类、友元成员函数和嵌套类是在其他类中声明的类;新增的特性:异常、运行阶段类型识别(RTTI)和改进后的类型转换控制。C++异常处理提供了处理特殊情况的机制,如果不对其进行处理,将导致程序终止。RTTI是一种确定对象类型的机制。新的类型转换运算符提高了类型转换的安全性。可以将类作为友元,在这种情况下,友元类的所有方法都可以访问原始类的私有成员和保护成员。¬¬也可以只将特定的成员函数指定为另一个类的友元。当函数需要访问两个类的私有数据时,这就需要使用友元。例如,假定有一个Probe类和一个Analyzer类

小米子的成长日记 595

C++类型转换

C++中的强制类型转换,static_cast、dynamic_cast、reinterpret_cast和const_cast四种强制类型转换

Brant_zero的博客 450

C++:类型转换

标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符: static_cast、reinterpret_cast、const_cast、dynamic_cast

decade777555的博客 828

UEC++中的RTTI

**RTTI**(Runtime Type Information,运行时类型信息)是C++语言提供的一种机制,允许在程序运行时获取对象的**类型信息**,RTTI通常用于处理多态性、类型转换和类型检查。

记录值得记录的东西 935
上一篇: 操作符重载之解引用与箭头操作符
下一篇: C++智能指针之auto_ptr
IT_Linux
博客等级 码龄14年 31粉丝 77原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值