C++之const_cast的用法

news2025/1/15 13:07:37

C++的四种类型转换之const_cast

这里写目录标题

    • 前言
    • const_cast
      • 1.new type为左值引用
      • 2. new type为函数类型的右值引用
      • 3.new type为对象类型的右值引用
      • 4.指向函数的指针和指向成员函数的指针不受约束
      • 5.通过非const访问路径修改const对象导致未定义行为
      • 6.const_cast只能用来修改指针,引用

前言

引用**《Effective C++ 中文版第三版》**中条款27 "尽量少做转型动作"中的一段话:

C++规则的设计目标之一是,保证“类型错误”绝对不可能发生,理论上如果你的程序很“干净”的通过编译,就表示它并不企图在任何对象上执行任何不安全、无意义、愚蠢荒谬的操作。这是一个极具价值的保证,可别草率的放弃它。

不幸的是,转型(cast)破坏了类型系统(type system),那可能导致任何种类的麻烦,有些容易辨识,有些非常隐晦。

 现实情况是类型转换在开发中无法避免,在开始探讨C++的类型转换以前我们先看下C风格的类型转换。

(T)varibale
T(variable)

 这种旧式类型转换目前依旧经常被用到,但是新式类型转换却更应该被我们去使用,这是因为:

  • 1.容易被辨识,从而更容易在程序出问题时找到问题所在

  • 2.职责划分更明细,编译器更可能在编译期找到问题。

  • 3.有更强的类型转换能力。

 目前C++提供的四种新式类型转换为

const_cast<T>()
dynamic_cast<T>()
reinterpret_cast<T>()
static_cast<T>()

 下面我们就const_cast,分别研究下其用途以及适用的使用场景

const_cast

const_cast<new type>(express)的主要用途是,移除对象的常量性,并且也是唯一具有此能力的C++风格的转型操作符

 在C++11中,const_cast可以完成以下类型转换

  • 两个可能指向同一类型的多级指针可以相互转换,而不考虑每一层上的cv性质(const and volatile)。
  • 空指针值可以转换为新类型的空指针值.

 可以看出,const_cast主要针对指针进行操作,其能力可以大概被总结为:

1、常量指针被转化成非常量的指针,并且仍然指向原来的对象;
2、常量引用被转换成非常量的引用,并且仍然指向原来的对象;

 const_cast的返回结果根据需要转换出的新类型,可以区别为:

  • 如果new type是lvalue引用,或者是函数类型的rvalue引用,则返回lvalue。
  • 如果new type是对象类型的rvalue引用,则返回xvalue。
  • 否则返回prvalue。

 以下时关于几个value的解释:

  • lvalue (Left-hand-side value)
  • rvalue (Right-hand-side value)
  • xvalue (eXpiring value)
  • prvalue (Pure rvalue)
  • glvalue (Generalized lvalue)

 For all the values, there were only two independent properties:

  • “has identity” – i.e. an address, a pointer, the user can determine whether two copies are identical, etc.use “i” represent
  • “can be moved from” – i.e. we are allowed to leave to source of a “copy” in some indeterminate, but valid state.use “m” represent.

 There are four possible composition:

  • iM: has identity and cannot be moved from (defined as lvalue)
  • im: has identity and can be moved from (defined as xvalue)
  • Im: does not have identity and can be moved from (defined as prvalue)
  • IM: doesn’t have identity and cannot be moved (他认为这种情况在 C++ 中是没有用的)

 以上出自于https://cloud.tencent.com/developer/article/1493839

 需要注意的是,const_cast中:

  1. 指向函数的指针和指向成员函数的指针不受const_cast约束。
  2. const_cast可以形成一个指向非const类型的引用或指针,它实际上引用了一个const对象,也可以形成一个指向非volatile类型的引用或指针,它实际上引用了一个volatile对象。
  3. 通过非const访问路径修改const对象并通过非volatile glvalue引用volatile对象会导致未定义的行为。

未定义行为:C++标准对此类行为没有做出明确规定.同一份代码在使用不同的编译器会有不同的效果

《C++ Primer》《Effective C++》是C++开发者必不可少的书籍,如果你想入门C++,以及想要精进C++开发技术,这两本书可以说必须要有。此外,《Linux高性能服务器编程》以及《Linux多线程服务端编程:使用muduo C++网络库》.(陈硕)》是快速提高你的linux开发能力的秘籍。在网上搜索相关资源也要花费一些力气,需要的同学可以关注公众号【程序员DeRozan】,回复**【1207】**快速免费领取~

 下面通过例子来分析const_cast的用法,C++版本为C++11

1.new type为左值引用

 将一个常量左值引用转换为一个非常量左值引用:

 int i = 3; // i is not declared const
    const int &rci = i;
    const_cast<int &>(rci) = 4; // OK: modifies i
    std::cout << "i = " << i << '\n';

 控制台输出

sh-4.4$ ./build/linux/x86_64/release/Class-convert 
i = 4

 即,如果new type为左值引用,则返回值是一个左值

2. new type为函数类型的右值引用

 如果new type的类型为函数右值引用,则const_cast的返回值为左值

void printHello(){
    cout<<"hello world"<<endl;
}

void printHello2(){
    cout<<"hello world 2"<<endl;
}

int main(){
    
    const std::reference_wrapper<void()>x = std::ref(printHello);
    // x = printHello2; //编译错误,const类型的函数右值引用
    const_cast<std::reference_wrapper<void()> &&>(x) = printHello2;  
    x();
}

3.new type为对象类型的右值引用

 将一个常量对象右值引用,转换为一个非常量的对象类型引用:

class OBJ {
    public:
    int num;
    OBJ(int i){num = i;}
    ~OBJ(){}
};


int main()
{

    const OBJ&& obj = OBJ(1);
    cout<<"obj.num="<<obj.num<<endl;

    // obj.num = 3;  //编译错误,这里是const引用

    // const_cast<OBJ&&>(obj).num = 4;// 编译错误,error: using xvalue (rvalue reference) as lvalue
    // cout << "obj.num=" << obj.num<<endl;
    
    OBJ &&obj2 = const_cast<OBJ &&>(obj);  //编译通过
    obj2.num = 3;
    cout << "obj.num=" << obj.num << endl;
}

4.指向函数的指针和指向成员函数的指针不受约束

struct type
{
    int i;

    type() : i(3) {}

    void f(int v) const
    {
        // this->i = v;                 // compile error: this is a pointer to const
        const_cast<type *>(this)->i = v; // OK as long as the type object isn't const
    }
};
int main(){
      [[maybe_unused]] void (type::*pmf)(int) const = &type::f; // pointer to member function
    // const_cast<void(type::*)(int)>(pmf);   // compile error: const_cast does
    // not work on function pointers   
}

5.通过非const访问路径修改const对象导致未定义行为

    const int j = 3; // j is declared const
    [[maybe_unused]] int *pj = const_cast<int *>(&j);
    // *pj = 4;      // undefined behavior

6.const_cast只能用来修改指针,引用

   const int j = 3; // j is declared const
   int ppj = const_cast<int>(j); // 编译错误,invalid use of const_cast with type ‘int’, which is not a pointer, reference, nor a pointer-to-data-member type

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/387745.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android onLayout布局流程解析

组件布局流程结论 1.&#xff09;layout流程始于ViewRootImpl的performLayout()方法&#xff0c;该方法会调用根View&#xff08;DecorView&#xff09;的layout()方法进行布局&#xff0c;因为DecorView是ViewGroup(FrameLayout),所以layout流程来到了ViewGroup&#xff08;其…

【C语言指针练习题】你真的学会指针了吗?

✨✨✨✨如果文章对你有帮助记得点赞收藏关注哦&#xff01;&#xff01;✨✨✨✨ 文章目录✨✨✨✨如果文章对你有帮助记得点赞收藏关注哦&#xff01;&#xff01;✨✨✨✨一维数组练习题&#xff1a;字符数组练习题&#xff1a;字符指针练习题&#xff1a;二维数组练习题&am…

LeetCode-63. 不同路径 II

题目来源 63. 不同路径 II 递归 class Solution {public int uniquePathsWithObstacles(int[][] obstacleGrid) {int row obstacleGrid.length-1;int col obstacleGrid[0].length-1;return process(row,col,0,0,obstacleGrid);}private int process(int row ,int col,int i…

重装系统一半电脑蓝屏如何解决

小编相信大家在使用电脑或者给电脑重装系统的时候都遇到过电脑蓝屏等等故障问题。最近有用户就遇到了这样一个问题&#xff0c;问小编重装系统一半电脑蓝屏怎么办&#xff0c;那么今天小编就告诉大家重装系统一半电脑蓝屏的解决方法。 工具/原料&#xff1a; 系统版本&#x…

Tecent libco C++协程库初探

安装 https://github.com/Tencent/libco 上把release版本的下下来&#xff1a; mkdir build && cd build && cmake .. && make拿到动态和静态库啦&#xff0c;然后cp到/usr/local/lib就完成安装啦。 项目有很多example&#xff0c;直接进根目录make就…

phpinfo包含临时文件Getshell全过程及源码

目录 前言 原理 漏洞复现 靶场环境 源码 复现过程 前言 PHP LFI本地文件包含漏洞主要是包含本地服务器上存储的一些文件&#xff0c;例如session文件、日志文件、临时文件等。但是&#xff0c;只有我们能够控制包含的文件存储我们的恶意代码才能拿到服务器权限。假如在服…

B. Sherlock and his girlfriend

Sherlock has a new girlfriend (so unlike him!). Valentines day is coming and he wants to gift her some jewelry. He bought n pieces of jewelry. The i-th piece has price equal to i  1, that is, the prices of the jewelry are 2, 3, 4, ... n  1. Watson…

跳表--C++实现

目录 作者有话说 为何要学习跳表&#xff1f;为了快&#xff0c;为了更快&#xff0c;为了折磨自己..... 跳表作用场景 1.不少公司自己会设计哈希表&#xff0c;如果解决哈希冲突是不可避免的事情。通常情况下会使用链址&#xff0c;很好理解&#xff0c;当有冲突产生时&#…

深度学习训练营之识别宝可梦人物和角色

深度学习训练营之识别宝可梦人物和角色原文链接环境介绍前置工作设置GPU数据加载数据查看数据预处理加载数据可视化数据检查数据配置数据集prefetch()功能详细介绍&#xff1a;调用官方的网络的模型模型训练官方模型调用设置动态学习率模型训练模型评估结果分析参考链接原文链接…

【Redis】Redis 如何实现分布式锁

Redis 如何实现分布式锁1. 什么是分布式锁1.1 分布式锁的特点1.2 分布式锁的场景1.3 分布式锁的实现方式2. Redis 实现分布式锁2.1 setnx expire2.2 set ex px nx2.3 set ex px nx 校验唯一随机值&#xff0c;再删除2.4 Redisson 实现分布式锁1. 什么是分布式锁 分布式锁其实…

【C语言进阶:指针的进阶】回调函数

本章重点内容&#xff1a; 字符指针指针数组数组指针数组传参和指针传参函数指针函数指针数组指向函数指针数组的指针回调函数指针和数组面试题的解析什么是回调函数&#xff1a; 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针&#xff08;地址&#xff09;作…

Lenovo 联想-IdeaPad-Y530电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。硬件型号驱动情况主板联想-IdeaPad-Y530处理器Intel 酷睿2双核 T9400已驱动内存2GB已驱动硬盘2TB HP EX950 PCI-E Gen3 x4 NVMe SSD已驱动显卡NVIDIA GeForce 9300M GS无法驱动声卡Realtek ALC888无法驱动网卡RTL8168H Giga…

【Java学习笔记】3.Java 基础语法

Java 基础语法 一个 Java 程序可以认为是一系列对象的集合&#xff0c;而这些对象通过调用彼此的方法来协同工作。下面简要介绍下类、对象、方法和实例变量的概念。 对象&#xff1a;对象是类的一个实例&#xff0c;有状态和行为。例如&#xff0c;一条狗是一个对象&#xff…

【NLP相关】从零开始理解BERT模型:NLP领域的突破(BERT详解与代码实现)

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

Python异常处理更新,正常和不正常的都在这里

嗨害大家好鸭&#xff01;我是小熊猫~ 异常处理篇嗨害大家好鸭&#xff01;我是小熊猫~Python标准异常&#x1f4a8;什么是异常&#xff1f;不正常异常处理&#x1f4a8;使用except而不带任何异常类型使用except而带多种异常类型try-finally 语句异常的参数触发异常用户自定义异…

Lesson12---人工神经网络(1)

12.1 神经元与感知机 12.1.1 感知机 感知机&#xff1a; 1957&#xff0c; Fank Rosenblatt 由两层神经元组成&#xff0c;可以简化为右边这种&#xff0c;输入通常不参与计算&#xff0c;不计入神经网络的层数&#xff0c;因此感知机是一个单层神经网络 感知机 训练法则&am…

MyBatis - 13 - MyBatis逆向工程

文章目录1.准备工作1.1 建表1.2 创建Maven工程1.2.1 在pom.xml中添加依赖和插件&#xff0c;更新maven1.2.2 在src/main/resources下创建mybatis-config.xml1.2.3 在src/main/resources下创建jdbc.properties1.2.4 在src/main/resources下创建log4j.xml文件1.2.5 在src/main/re…

搭建zabbix4.0监控服务实例

一.Zabbix服务介绍 1.1服务介绍 Zabbix是基于WEB界面的分布式系统监控的开源解决方案&#xff0c;Zabbix能够监控各种网络参数&#xff0c;保证服务器系统安全稳定的运行&#xff0c;并提供灵活的通知机制让SA快速定位并解决存在的各种问题。 1.2 Zabbix优点 Zabbix分布式监…

python用openpyxl包操作xlsx文件,统计表中合作电影数目最多的两个演员

题目&#x1f389;&#x1f389;&#x1f389;&#xff1a;编程完成下面任务&#xff1a;已知excel文件“电影导演演员信息表.xlsx”如下图所示&#xff1a;&#x1f373;&#x1f373;&#x1f373;要求&#xff1a;使用 openpyxl 包操作打开此文件&#xff0c;编写程序统计在…

sqlli-labs基本使用

1.安装hackbar插件 链接&#xff1a;https://pan.baidu.com/s/1-QIYmAU-BV_DEONfxovizQ 提取码&#xff1a;dc66 2.SQL注入表信息解析&#xff08;案例使用的sqlli-labs自带的数据库security&#xff09; 2.1 通过order by 判断表有多少列 分析表有多少列&#xff08;通过…