前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >RTTI和类型转换运算符

RTTI和类型转换运算符

作者头像
艰默
发布2022-12-12 10:22:39
5940
发布2022-12-12 10:22:39
举报
文章被收录于专栏:iDoitnow

目录

  • 1. RTTI
    • 1.1 RTTI的三个元素
  • 2. 类型转换运算符
    • 2.1 dynamic_cast
    • 2.2 const_cast
    • 2.3 static_cast
    • 2.4 reinterpret_cast

1. RTTI

RTTI是运行阶段类型识别(Runtime Type Identification)的简称。该特性是为了程序在运行阶段确定对象类型提供一种标准方式。

1.1 RTTI的三个元素

由于只有包含虚函数的类层次结构,才能将派生类对象的地址赋给基类指针,因此RTTI只适用包含虚函数的类。

  • dynamic_cast运算符将使用一个指向基类的指针来生成一个指向派生类的指针,否则,该运算符返回0—空指针。
  • typied运算符返回一个指出对象的类型的值。
  • type_info结构存储了有关特定类型的信息。
1.1.1 dynamic_cast运算符

dynamic_cast运算符是RTTI中最常用的组件,其主要的功能是确定是否可以安全地将对地址赋给特定类型的指针,如果可以则返回该特定类型的指针,如果不可以则返回0(空指针)。可以理解为dynamic_cast可以用来类型转换,如果可安全转换,则转换成相应的类型指针,否则直接返回0(空指针)。其语法如下:

代码语言:javascript
复制
dynamic_cast<type_name> (expression)

例如下面的例子:

代码语言:javascript
复制
class Base{
    private:
    double val;
    public:
    Base(double a = 0):val(a){}
    virtial void show(){std::cout<<"Base show!"<< std::endl();}
}

class BaseA:public: Base{
    BaseA(double a = 0):Base(a){}
    virtual void show(){std::cout <<"BaseA show!"<<std::endl;}
    virtual void display(){std::cout<<"BaseA val: "<<val<<std::endl;}
}

class BaseB:public: BaseA{
    BaseB(double a = 0):BaseA(a){}
    virtual void show(){std::cout <<"BaseB show!"<<std::endl;}
    virtual void display(){std::cout<<"BaseB val: "<<val<<std::endl;}
}

假设有下面的指针:

代码语言:javascript
复制
Base* bs = new Base;
Base* ba = new BaseA;
Base* bb = new BaseB;

对于下面类型的转换:

代码语言:javascript
复制
BaseB* b1 = dynamic_cast<BaseB*>(bb)//毫无疑问派生类到基类的转换是安全的,该返回值类型即Base*
BaseA* b2 = dynamic_cast<BaseA*>(bs)//由于Base中无dispaly的实现,该转换存在安全风险,因此b2为0(空指针)

因此针对该例子,dynamic_cast常用的场景如下:

代码语言:javascript
复制
auto bs = new BaseX;//BaseX为Base、BaseA、BaseB中的任意一种类型,假设其具体类型只有在程序运行过程中才能确定。
BaseA* pa;
if(pa = dynamic_cast<BaseA*>(bs))
{
    ps->display();
}
1.1.2 typeid运算符

typeid运算符能够确定两个对象是否为同种类型,其可以接受两种参数:

  • 类名;
  • 结果为对象的表达式。

其返回一个type_info对象的引用,其实方法如下:

代码语言:javascript
复制
//需要包含头文件#include<typeinfo>
A* a = new A;//A为一个类
if(typeid(A) == typeid(*a)){
    std::cout << "a的类型为A"<<std::endl;
}
else
{
    std::cout << "a的类型不为A"<<std::endl;
}

针对上例,若a是一个空指针,则typeid(*a)会引发bad_typeid异常,该异常类型是从exception类派生出来,也是在typeinfo中生声明的。

1.1.3. type_info类

type_info类主要存储了有关特定类型的信息,其中包含了一个name()成员,该成员函数主要用于调试,其需要与typeid搭配使用,使用方法如下:

代码语言:javascript
复制
//class A;
A* a = new A;
std::cout<<typeid(*a).name()<<std::endl;//输出结果为A

2. 类型转换运算符

2.1 dynamic_cast

前面已经介绍过其用法,该运算符的主要用途是,使得能够在类层次结构中进行向上转换(即派生类到基类的转换,由于该转换是is-a的关系,所以该转换是安全的),而不允许其他的转换。

2.2 const_cast

const_cast运算符用于执行只有一种用途的类型转化,即改变constvolatile,其语法与dynamic_cast相同:

代码语言:javascript
复制
const_cast <type_name> (expression)

如果类型的其他方面也被修改,则上述类型转换将出错,也就是说除了constvolatile特征(有或无)可以不同外,type_nameexpression的类型必须相同。假设AB,则有下面的转换:

代码语言:javascript
复制
A a;
const A* pa = &a;
A* pa1 = const_cast<A*>(pa); //正确
const B* pb = const_cast<const B*>(pa);//错误

提供该运算符的原因是,程序有时候可能需要一个这样的值,它在大多数的时候是常量,而有时候又是可以修改的,在这种情况下,可以将这个值声明为const,并在需要修改它的时候,使用const_cast

2.3 static_cast

static_cast运算符与其他类型转换运算符的语法一样:

代码语言:javascript
复制
 static_cast <type_name> (expression)

static_castexpression转换为type_name类型,主要用于非多态类型之间的转换,不提供运行时的检查来确保转换的安全性。主要在以下几种场合中使用:

  • 用于类层次结构中,基类和子类之间指针和引用的转换;当进行上行转换(把派生类的指针或引用转换成基类表示),这种转换是安全的;当进行下行转换(把基类的指针或引用转换成派生类表示),这种转换是不安全的,也需要程序员来保证;
  • 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum等等,这种转换的安全性需要程序员来保证;
  • 把void指针转换成目标类型的指针,是极其不安全的,也需要程序员来保证;

2.4 reinterpret_cast

reinterpret_cast运算符与其他类型转换运算符的语法一样:

代码语言:javascript
复制
reinterpret_cast <type_name> (expression)

reinterpret_cast运算符用于天生危险的类型转换,因为其允许将任何指针类型转换为其它的指针类型。reinterpret_cast 运算符并不会改变括号中运算对象的值,而是对该对象从位模式上进行重新解释。它主要用于将一种数据类型从一种类型转换为另一种类型。例如,它可以将一个指针转换成一个整数,也可以将一个整数转换成一个指针,然而,其并不支持所有类型的转换,例如,可以将指针类型转换为足以存储指针表示的整形,但不能将指针转换为更小的整形或浮点型。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-12-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iDoitnow 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. RTTI
    • 1.1 RTTI的三个元素
      • 1.1.1 dynamic_cast运算符
      • 1.1.2 typeid运算符
      • 1.1.3. type_info类
  • 2. 类型转换运算符
    • 2.1 dynamic_cast
      • 2.2 const_cast
        • 2.3 static_cast
          • 2.4 reinterpret_cast
          相关产品与服务
          对象存储
          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档