C++强制类型转换运算符-dynamic_cast、const_cast、static_cast、reinterpret_cast、dynamic_pointer_cast、const_pointer

2023-11-10

C++强制类型转换

dynamic_cast

回答的问题:是否能将某个对象的地址安全地赋值给一个特定类型的指针;同时也回答了强制类型转换是否安全的问题。
dynamic_cast用于类继承层次间的指针或引用转换。主要还是用于执行安全的向下转型(safe downcasting),两种情况:

  • 基类指针所指对象是派生类类型的,将其转换为派生类型的指针,是安全的,转换成功。
  • 基类指针所指对象为基类类型,要将其转换为派生类型指针,这是不安全的,转换失败。

向上转型本身就是安全的,即基类指针可以指向派生类指针,可以直接使用=符号,无需使用dynamic_cast运算符。

格式:dynamic_cast<Type *>(pt)
    pt能否安全的类型转换(*pt为Type或者*pt为Type的继承类)为Type *,如果可以,则返回pg的地址;反之,返回0
也可以使用引用(应该不常用)dynamic_cast<Superb &>(rg)
    pt能否安全的类型转换(pt为Type或者pt为Type的继承类)为Type &,如果可以,则返回pg的地址;反之,引发bad_cast异常(在typeinfo头文件中)

const_cast

  • 主要用途:对于常量指针,移除对象的常量性。
  • 转换格式:const_cast < type-name > (expression)
  • 要求:type-name和expression必须是同一种类型,他们只在const和volatile上存在区别,转换成功就赋值就行,转换失败则返回0。
  • volatile:提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。
  • 与常规类型转换的不同:常规类型转换可以转换为不同类型,但是const_cast不允许不同类型的转换
  • 基本原则:不允许将定义为const的变量转换为非const类型(这个是针对非指针)。

分几种情况:其实就是基本原则的体现

  • 原来就是常量,用一个常量指针指向它,要将这个常量指针转换为非常量指针并修改其值,这是不允许的。
  • 原来不是常量,用一个常量指针指向它,要将这个常量指针转换为非常量指针并修改其值,这是允许的。

static_cast

格式:static_cast < type-name > (expression)
当且仅当type-name类型可以隐式转换为expression类型,或反之,否则类型转换会报错,两者能互相转换

允许的转换

  • 允许向上转换(继承类指针转换为基类指针)
  • 允许向下转换(基类指针转换为继承类指针)
  • 由于枚举类可以隐式转换为int,因此static_cast允许这类转换,并且允许将int类型转换为枚举类
  • 允许将double转换为int,将int转换为double
  • 允许将float转换为long,允许将long转换为float

不允许的转换

  • 不同类型的指针之间互相转换
  • 非指针类型和指针类型之间的相互转换
  • 不同类型的引用之间的转换

reinterpret_cast

格式:reinterpret_cast < type-name > (expression)
转换时,执行的是逐个比特复制的操作。转换的安全性由程序员负责。

允许的转换:

  • 可以将指针类型转换为能够容纳该指针类型的整型,反之不能转换。
  • 不同类型的指针之间的转换
  • 不同类型的引用之间的转换

不允许的转换:

  • 不能将函数指针转换为数据指针

代码

rtti1.h

#pragma once
#include <iostream>
using std::cout;
#ifndef _RTTI1_H_
#define _RTTI1_H_
class Grand
{
private:
    int hold;

public:
    Grand(int h = 0) : hold(h) {}
    virtual void Speak() const { cout << "I am a grand class!\n"; }
    virtual int Value() const { return hold; }
};
class Superb : public Grand
{
public:
    Superb(int h = 0) : Grand(h) {}
    void Speak() const { cout << "I am a superb class!!\n"; }
    virtual void Say() const
    {
        cout << "I hold the superb value of " << Value() << "!\n";
    }
};
class Magnificent : public Superb
{
private:
    char ch;

public:
    Magnificent(int h = 0, char c = 'A') : Superb(h), ch(c) {}
    void Speak() const { cout << "I am a magnificent class!!!\n"; }
    void Say() const
    {
        cout << "I hold the character " << ch << " and the integer " << Value() << "!\n";
    }
};
#endif

main.cpp

#include <iostream>
#include <cstdlib>
#include <ctime>
#include "rtti1.h"
using std::cout;
using std::endl;

Grand *GetOne();
void change(const int *pt, int n);
int main()
{
    /*
    dynamic_cast:
        dynamic_cast是最常用的RTTI操作符。
        回答的问题:是否能将某个对象的地址安全地赋值给一个特定类型的指针;同时也回答了强制类型转换是否安全的问题
        格式:dynamic_cast<Type *>(pt)
            pt能否安全的类型转换(*pt为Type或者*pt为Type的继承类)为Type *,如果可以,则返回pg的地址;反之,返回0
        也可以使用引用(应该不常用):dynamic_cast<Superb &>(rg)
            pt能否安全的类型转换(pt为Type或者pt为Type的继承类)为Type &,如果可以,则返回pg的地址;反之,引发bad_cast异常(在typeinfo头文件中)
    */
    cout << "dynamic_cast***************************************************************" << endl;
    std::srand(std::time(0));
    Grand *pg;
    Superb *ps;
    for (int i = 0; i < 5; i++)
    {
        pg = GetOne();
        pg->Speak();
        if (ps = dynamic_cast<Superb *>(pg)) // 如果可以转换,则if条件判断为1,则执行ps->Say();反之,不执行
            ps->Say();
    }
    /*
    const_cast:
        转换格式:const_cast < type-name > (expression)
        要求:type-name和expression必须是同一种类型,他们只在const和volatile上存在区别,转换成功就赋值就行,转换失败则返回0
        与常规类型转换的不同:常规类型转换可以转换为不同类型,但是const_cast不允许不同类型的转换
        基本原则:不允许将定义为const的变量转换为非const类型。
    */
    cout << "const_cast***************************************************************" << endl;
    int pop1 = 38383;
    const int pop2 = 2000;
    cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
    change(&pop1, -103); // 转换了,因为pop1是非const类型
    change(&pop2, -103); // 没转换,因为pop2是const类型
    cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
    /*
    static_cast:
        格式:static_cast < type-name > (expression)
        当且仅当type-name类型可以隐式转换为expression类型,或反之,否则类型转换会报错,两者能互相转换
        1.允许向上转换(继承类指针转换为基类指针)
        2.允许向下转换(基类指针转换为继承类指针)
        3.由于枚举类可以隐式转换为int,因此static_cast允许这类转换,并且允许将int类型转换为枚举类
        4.允许将double转换为int,将int转换为double
        5.允许将float转换为long,允许将long转换为float
    */
    cout << "static_cast***************************************************************" << endl;
    Grand x = Grand(10);   // 基类对象
    Grand *w = &x;         // 基类指针
    Superb z = Superb(11); // 继承类对象
    Superb *pointer1 = &z;
    Superb *y = static_cast<Superb *>(w);      // 将基类指针转换为继承类指针 允许
    y->Speak();                                // 只是允许但是不推荐,因为转换为继承类指针后可以调用继承类的成员方法,而基类没有该成员方法,会引发异常
    Grand *a = static_cast<Grand *>(pointer1); // 将继承类指针转换为基类指针
    a->Speak();
    int varint1 = 99;
    double vardouble1 = 99.99;
    int var = static_cast<int>(vardouble1);
    std::cout << "var = " << var << std::endl;
    double var1 = static_cast<double>(varint1);
    std::cout << std::fixed << "var1 = " << var1 << std::endl;
    /*
    reinterpret_cast:
        格式:reinterpret_cast < type-name > (expression)
        可以将指针类型转换为能够容纳该指针类型的整型,反之不能转换。
        不能将函数指针转换为数据指针
    */
    struct dat
    {
        short a;
        short b;
    };
    long value = 0xA224B118;
    dat *pd = reinterpret_cast<dat *>(&value);
    std::cout << std::hex << pd->a; // display first 2 bytes of value

    return 0;
}
Grand *GetOne() // generate one of three kinds of objects randomly
{
    Grand *p = 0;
    switch (std::rand() % 3)
    {
        case 0:
            p = new Grand(std::rand() % 100);
            break;
        case 1:
            p = new Superb(std::rand() % 100);
            break;
        case 2:
            p = new Magnificent(std::rand() % 100,
                                'A' + std::rand() % 26);
            break;
    }
    return p;
}

void change(const int *pt, int n)
{
    int *pc;
    pc = const_cast<int *>(pt);
    *pc += n;
}

运行结果:

C:\Users\15495\Documents\Jasmine\Work\coding\cmake-build-debug\coding.exe
dynamic_cast***************************************************************
I am a magnificent class!!!
I hold the character A and the integer 23!
I am a superb class!!
I hold the superb value of 8!
I am a superb class!!
I hold the superb value of 54!
I am a magnificent class!!!
I hold the character R and the integer 72!
I am a magnificent class!!!
I hold the character Q and the integer 65!
const_cast***************************************************************
pop1, pop2: 38383, 2000
pop1, pop2: 38280, 2000
50
100
static_cast***************************************************************
I am a grand class!
I am a superb class!!
var = 99
var1 = 99.000000
b118
Process finished with exit code 0

智能指针强制类型转换

dynamic_pointer_cast

适用对象:shared_ptr。
格式:std::shared_ptr<Superb> ps = std::dynamic_pointer_cast<Superb>(pa)
函数原理:首先,把指针拿出来,然后通过dynamic转化指针类型,然后再生成对应的智能指针,三个步骤。源码如下:

template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
dynamic_pointer_cast(const shared_ptr<_Up>& __r) noexcept
{
    using _Sp = shared_ptr<_Tp>;
    if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get()))
        return _Sp(__r, __p);
    return _Sp();
}

如果需要对std::unique_ptr进行转换,可以模仿这个方式自己写,在标准库中,并没有提供。

const_pointer_cast

template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
const_pointer_cast(const shared_ptr<_Up>& __r) noexcept
{
    using _Sp = shared_ptr<_Tp>;
    return _Sp(__r, const_cast<typename _Sp::element_type*>(__r.get()));
}

static_pointer_cast

template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
static_pointer_cast(const shared_ptr<_Up>& __r) noexcept
{
    using _Sp = shared_ptr<_Tp>;
    return _Sp(__r, static_cast<typename _Sp::element_type*>(__r.get()));
}

reinterpret_pointer_cast

template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
reinterpret_pointer_cast(const shared_ptr<_Up>& __r) noexcept
{
    using _Sp = shared_ptr<_Tp>;
    return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get()));
}

代码

rtti1.h

#pragma once
#include <iostream>
using std::cout;
#ifndef _RTTI1_H_
#define _RTTI1_H_
class Grand
{
private:
    int hold;

public:
    Grand(int h = 0) : hold(h) {}
    virtual void Speak() const { cout << "I am a grand class!\n"; }
    virtual int Value() const { return hold; }
};
class Superb : public Grand
{
public:
    Superb(int h = 0) : Grand(h) {}
    void Speak() const { cout << "I am a superb class!!\n"; }
    virtual void Say() const
    {
        cout << "I hold the superb value of " << Value() << "!\n";
    }
};
class Magnificent : public Superb
{
private:
    char ch;

public:
    Magnificent(int h = 0, char c = 'A') : Superb(h), ch(c) {}
    void Speak() const { cout << "I am a magnificent class!!!\n"; }
    void Say() const
    {
        cout << "I hold the character " << ch << " and the integer " << Value() << "!\n";
    }
};
#endif

main.cpp

#include <iostream>
#include <cstdlib>
#include <ctime>
#include "rtti1.h"
#include <Memory>
using std::cout;
using std::endl;

std::shared_ptr<Grand> GetOne();
void change(const std::shared_ptr<int> pt, int n);
int main()
{
    cout << "dynamic_pointer_cast***************************************************************" << endl;
    std::srand(std::time(0));
    std::shared_ptr<Grand> pg = nullptr;
    std::shared_ptr<Superb> ps = nullptr;
    for (int i = 0; i < 5; i++)
    {
        pg = GetOne();
        pg->Speak();
        if (ps = std::dynamic_pointer_cast<Superb>(pg)) // 如果可以转换,则if条件判断为1,则执行ps->Say();反之,不执行
            ps->Say();
    }
    cout << "const_pointer_cast***************************************************************" << endl;
    int pop1 = 38383;
    const int pop2 = 2000;
    std::shared_ptr<int> po1(&pop1);
    std::shared_ptr<const int> po2(&pop2);
    cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
    int n = -103;
    // 转换成功
    std::shared_ptr<int> pc1 = nullptr;
    pc1 = std::const_pointer_cast<int>(po1);
    *pc1 += n;
    // 转换失败
    std::shared_ptr<int> pc2 = nullptr;
    pc2 = std::const_pointer_cast<int>(po2);
    *pc2 += n;
    cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
    cout << "static_pointer_cast***************************************************************" << endl;
    Grand x = Grand(10);   // 基类对象
    std::shared_ptr<Grand> w(&x);         // 基类指针
    Superb z = Superb(11); // 继承类对象
    std::shared_ptr<Superb> pointer1(&z);
    std::shared_ptr<Superb> y = std::static_pointer_cast<Superb>(w);      // 将基类指针转换为继承类指针 允许
    y->Speak();                                // 只是允许但是不推荐,因为转换为继承类指针后可以调用继承类的成员方法,而基类没有该成员方法,会引发异常
    std::shared_ptr<Grand> a = std::static_pointer_cast<Grand>(pointer1); // 将继承类指针转换为基类指针
    a->Speak();
    cout << "reinterpret_pointer_cast***************************************************************" << endl;
    struct dat
    {
        short a;
        short b;
    };
    // 这样转换其实是不安全的,程序员需要主动保证程序的安全性。
    // 本程序运行结束程序的返回值非0,是错的
    long value = 0xA224B118;
    std::shared_ptr<long> data(&value);
    std::shared_ptr<dat> pd = std::reinterpret_pointer_cast<dat>(data);
    std::cout << std::hex << pd->a; // display first 2 bytes of value
//    std::cout << std::hex << pd->b; // display first 2 bytes of value

    return 0;
}
std::shared_ptr<Grand> GetOne() // generate one of three kinds of objects randomly
{
    std::shared_ptr<Grand> p = nullptr;
    switch (std::rand() % 3)
    {
        case 0:
            p.reset(new Grand(std::rand() % 100));
            break;
        case 1:
            p.reset(new Superb(std::rand() % 100));
            break;
        case 2:
            p.reset(new Magnificent(std::rand() % 100,
                                'A' + std::rand() % 26));
            break;
    }
    return p;
}

运行结果:

C:\Users\15495\Documents\Jasmine\Work\coding\cmake-build-debug\coding.exe
I hold the character O and the integer 66!
I am a superb class!!
I hold the superb value of 49!
I am a magnificent class!!!
I hold the character V and the integer 33!
const_pointer_cast***************************************************************
pop1, pop2: 38383, 2000
pop1, pop2: 38280, 2000
static_pointer_cast***************************************************************
I am a grand class!
I am a superb class!!
reinterpret_pointer_cast***************************************************************
b118
Process finished with exit code -1073740940 (0xC0000374)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++强制类型转换运算符-dynamic_cast、const_cast、static_cast、reinterpret_cast、dynamic_pointer_cast、const_pointer 的相关文章

随机推荐

  • selenium对浏览器操作、鼠标操作等总结

    1 控制浏览器 Selenium 主要提供的是操作页面上各种元素的方法 但它也提供了操作浏览器本身的方法 比如浏览器的大小以及浏览器后退 前进按钮等 1 1 控制浏览器窗口大小 在不同的浏览器大小下访问测试站点 对测试页面截图并保存 然后观
  • OPEN-VOCABULARY OBJECT DETECTION VIAVISION AND LANGUAGE KNOWLEDGE DISTILLATION

    通过视觉和语言知识提炼进行开放词汇的物体检测 摘要 我们的目标是推进开放词汇的物体检测 它可以检测由任意文本输入描述的物体 根本的挑战是训练数据的可用性 现有的物体检测数据集只包含数百个类别 而且进一步扩展成本很高 为了克服这一挑战 我们提
  • 线程池状态

    1 RUNNING 接受新的任务 处理等待队列中的任务 2 SHUTDOWN 不接受新的任务提交 但是会继续处理等待队列中的任务 调用线程池的shutdown 方法时 线程池由RUNNING gt SHUTDOWN 3 STOP 不接受新的
  • Ubuntu1604安装ganglia并监控Hadoop/HBase/Spark集群

    ganglia的官方文档没找到 试了很多教程 终于配置成功 不过还有一点小问题没有解决 安装依赖软件apache php rrdtool ganglia需要使用apache服务 rrd服务 php服务 这里安装的是最新的php7 0 sud
  • 好盈电调拆解_拆解一个无刷电机调速器

    最近在研究无刷直流电机驱动 就把手头的一个无刷电机调速器拆开研究一下 SkyWalker 40A 电调是 好赢科技 生产的 最大电流为40A 拆解只需要一把刀划开外面的热缩管就可以了 拆开以后就能看到里面的电路板了 这是块4层板 两颗日本红
  • TV的端口

    TV信号 Audio 指的各种乐音的组合 频带为20Hz 20KHz 是人耳可以听到的范围 普通人可以听到的范围大概 100Hz 16KHz Video 随着科技的发展 视频信号也不断推陈出新 主要体现在数字化和高分辨率方面 AV 复合视频
  • 第21课 微信小程序视频标签显示弹幕

    第21课 微信小程序视频标签显示弹幕 效果图如下 wxml代码如下
  • QT的qRegisterMetaType和qRegisterMetaType

    以下只为自己的问题做个记录 参考理解 qRegisterMetaType使用方法如下 1 注册位置 在第一次使用此类链接跨线程的signal slot之前 一般在当前类的构造函数中进行注册 2 注册方法 在当前类的顶部包含 include
  • 华为OD机试 - 称砝码(Java)

    题目描述 现有n种砝码 重量互不相等 分别为 m1 m2 m3 mn 每种砝码对应的数量为 x1 x2 x3 xn 现在要用这些砝码去称物体的重量 放在同一侧 问能称出多少种不同的重量 输入描述 对于每组测试数据 第一行 n 砝码的种数 范
  • 小程序跳转带参数

    携带参数 pages reg reg wx navigateTo url pages promise promise name pages reg reg 接收参数 onLoad function arg console log sssss
  • Python安装教程步骤2:Windows中创建虚拟环境安装Pytorch并在PyCharm中配置虚拟环境

    python安装教程步骤2 windows中Anaconda创建虚拟环境安装pytorch并在pycharm中使用虚拟环境 作者介绍 windows中Anaconda创建虚拟环境安装pytorch 1 添加镜像源 2 创建虚拟环境 3 进入
  • SVN 客户端 设置上传过滤文件类型和文件夹

    第一步 编辑SVN 全局配置 修改如下内容 global ignores o lo la al libs so so 0 9 a pyc pyo class target target classpath project settings
  • python-爬虫

    对于自动化办公而言 网络数据的批量获取完数据可以节约相当的时间 因此爬虫在自动化办公中占据了一个比较重要的位置 Requests简介 Requests是一款目前非常流行的http请求库 使用python编写 能非常方便的对网页Request
  • Winform 登录页面创建和设置

    Winform 登录页面设置 自带的Form1进行改造 更换名字为FrmLogin 简单先不放置容器 直接先托两个TextBox 再放两个lable分别改好名字 设置密码框的textbox的PasswordChar设置为 再拖两个普通的bu
  • 语音识别研究的四大前沿方向

    以下转自 http blog csdn net whaoxysh article details 19402337 鸡尾酒会问题 cocktail party problem 是在计算机语音识别领域的一个问题 当前语音识别技术已经可以以较高
  • 微信小程序实现滑动/点击切换Tab

    背景 swiper scroll view实现滑动 点击切换Tab 以及scroll left的使用 文末分享源代码 记得点赞 关注 收藏 1 实现效果 2 实现步骤 2 1 scroll view实现tab列表 scroll view 可
  • react+antd 修改主题色

    项目使用的时 react 框架 和 ant design ui组件库 antd 官网中对定制主体是这样说的 详见 https ant design docs react customize theme cn 官网说的是 antd 的样式使用
  • Python中的几大产生随机数的函数range,randint以及xrange函数

    文章目录 1 xrange 函数 2 range 函数 3 randint 函数 示例代码 1 xrange 函数 现在python的版本大多都已经采用python3 x版本 python2 x版本已经逐渐不被人们所使用 xrange 函数
  • linux图形界面切换到字符界面

    redhat linux图形界面切换到字符界面 1 X Window图形界面和字符界面自由切换 一 图形界面切换到字符界面 在X Window图形操作界面中按 Alt Ctrl Fn n 1 6 就可以进入Console字符操作界面 这就意
  • C++强制类型转换运算符-dynamic_cast、const_cast、static_cast、reinterpret_cast、dynamic_pointer_cast、const_pointer

    C 强制类型转换 dynamic cast 回答的问题 是否能将某个对象的地址安全地赋值给一个特定类型的指针 同时也回答了强制类型转换是否安全的问题 dynamic cast用于类继承层次间的指针或引用转换 主要还是用于执行安全的向下转型