【C++】类型转换 ⑤ ( 常量和非常量之间的类型转换 - 常量类型转换 const_cast | const 左数右指原则 | 代码示例 )

文章目录

  • 一、const 关键字简介
    • 1、const 修饰普通数据
    • 2、const 修饰指针 ( 左数右指原则 | 指针常量 | 常量指针 )
  • 二、常量和非常量 之间的类型转换 - 常量类型转换 const_cast
    • 1、常量类型转换 const_cast
    • 2、常量不能直接修改
    • 3、修改常量值的方法
    • 4、特别注意 - 确保指针指向的空间可修改


在之前写过一篇 C++ 类型转换的博客 【C++ 语言】类型转换 ( 转换操作符 | const_cast | static_cast | dynamic_cast | reinterpret_cast | 字符串转换 ) , 简单介绍了 C++ 类型转换 ;

在 博客 【C++】类型转换 ① ( C 中的类型转换 | C++ 类型转换操作符 | const_cast | static_cast | dynamic_cast | reinterpret_cast ) 将 C 语言 和 C++ 中的类型转换进行了对比 ;

在 博客 【C++】类型转换 ② ( C++ 静态类型转换 static_cast | C 语言隐式转换弊端 | 代码示例 ) 中 , 主要分析了 静态类型转换 static_cast , 可以解决 C 语言隐式转换的弊端 ;

在博客 【C++】类型转换 ③ ( 重新解释类型转换 reinterpret_cast | 指针类型数据转换 ) 分析了 指针数据类型的转换 , 在 C 语言环境下 , 可以使用显示强制类型转换 , 在 C++ 环境中只能使用 重新解释类型转换 reinterpret_cast ;

在博客 【C++】类型转换 ④ ( 子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast ) 中 , 分析 C++ 环境下 使用 各种方式 进行 父类 和 子类 类型之间的转换 , 推荐使用 动态类型转换 dynamic_cast ;


本博客中 , 介绍 常量和非常量 之间的类型转换 , C++ 中推荐使用 常量类型转换 const_cast ;





一、const 关键字简介




1、const 修饰普通数据


普通类型数据的常量定义时 , const 关键字 在 数据类型 的 左边 和 右边 其作用 是相同的 ;

    // 下面两种 const 用法效果相同
    // 定义普通类型 ( 非指针类型 ) 的常量 const 在 类型左右 都是相同的
    const int a = 10;
    int const b = 20;

2、const 修饰指针 ( 左数右指原则 | 指针常量 | 常量指针 )


左数右指原则 : 指针 或 数据 的相关常量类型 ;

  • const 在 * 左边 ( 常量指针 | const 修饰的是数据 | 数据是常量不能修改 ) : 如果 const 修饰的是 指针变量 指向的内存空间 ,const char *c , const 修饰的是 char , char 数据不能被修改 , 这是 常量指针 , 指向常量的指针 ;
    • const 关键字在 指针符号 * 左侧 表示该定义的事 常量指针 ( 指向的内存数据不能修改 )
    // 左数右指 : const 在指针左边 数据是常量 , const 在指针右边 指针是常量
    // 下面两种情况 const 在指针左边 , 数据是常量 , 内存中的数据不能修改
    //      但是 , c 和 d 指针的指向可以修改
    // 下面两种情况是相同的
    const int* c;
    int const* d;
  • const 在 * 右边 ( 指针常量 | const 修饰的是指针 | 指针是常量不能修改 ) : 如果 const 修饰的是 指针变量 , 如 char * const d , const 修饰的是 char * , 指针不能被修改 ; 这是 指针常量 ;
    • const 关键字在 指针符号 * 右侧是 表示定义的事指针常量 ( 指针本身不能被修改 ) ;
    // 左数右指 : const 在指针左边 数据是常量 , const 在指针右边 指针是常量
    // 下面的情况 const 在指针右边 , 指针是常量 , 指针地址不能修改 
    //      但是 , 指针指向的内存中的数据可以修改
    int* const e = (int*)malloc(10);




二、常量和非常量 之间的类型转换 - 常量类型转换 const_cast




1、常量类型转换 const_cast


const 关键字 既可以修饰 指针 , 又可以修饰 普通类型数据 ;

  • const 修饰 指针 , 遵循左数右指原则 , const 在 * 左侧 数据是常量 不能修改 ( 常量指针 ) , const 在 * 右侧 指针是常量 不能修改 ( 指针常量 ) ;
  • const 修饰的普通常量 , const 在数据类型的左右两侧都可以 ;

常量类型转换 const_cast 可以 将 常量类型 转为 变量类型 , 以及 将 变量类型 转为 常量类型 ;

常量类型转换 const_cast 最大的作用就是 去掉 只读属性 ;


2、常量不能直接修改


函数接收一个 常量字符串 , const char * p 表示修饰的数据是常量 , 指针指向的 字符串 数据不可更改 ;

// const char * p 表示修饰的数据是常量 , 数据不可更改
void fun(const char * p)
{
	// 直接修改 const char * p 的数据内容会报错
	p[0] = 'A';
}

上述函数在编译时 , 就会报错 : error C3892: “p”: 不能给常量赋值 ;

已启动生成…
1>------ 已启动生成: 项目: HelloWorld, 配置: Debug Win32 ------
1>Test.cpp
1>D:\002_Project\006_Visual_Studio\HelloWorld\HelloWorld\Test.cpp(8,5): error C3892: “p”: 不能给常量赋值
1>已完成生成项目“HelloWorld.vcxproj”的操作 - 失败。
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0==========

在这里插入图片描述


3、修改常量值的方法


如果想要在函数中 , 修改常量值 , 可以使用 常量类型转换 const_cast , 先将 常量 转为变量 , 然后再进行修改 ;


在下面的代码中 , const char * p 表示修饰的数据是常量 , 数据不可更改 ;

如果想要修改 常量指针 指向的内存中的数据 ,

要使用 常量类型转换 const_cast , 将 常量指针 改为 变量指针 , 取消 指针指向的 内存空间 的 只读属性 , char* tmp = const_cast<char*>(str) ;

然后可以借助 转换成 变量指针 的 tmp 指针 , 改变指针指向内存中的数据 ;

// const char * p 表示修饰的数据是常量 , 数据不可更改
void fun(const char * str)
{
	cout << " 函数开始 : " << str << endl;

	// 直接修改 const char * p 的数据内容会报错
	// 报错 : error C3892: “p”: 不能给常量赋值
	//p[0] = 'A';

	char* tmp = const_cast<char*>(str);
	tmp[0] = 'A';

	cout << " 函数结束 : " << str << endl;
}

完整代码示例 :

#include "iostream"
using namespace std;

// const char * p 表示修饰的数据是常量 , 数据不可更改
void fun(const char * str)
{
	cout << " 函数开始 : " << str << endl;

	// 直接修改 const char * p 的数据内容会报错
	// 报错 : error C3892: “p”: 不能给常量赋值
	//p[0] = 'A';

	char* tmp = const_cast<char*>(str);
	tmp[0] = 'A';

	cout << " 函数结束 : " << str << endl;
}

int main() {

	char str[] = "Tom";
	fun(str);

	cout << " 程序结束 : " << str << endl;


	// 控制台暂停 , 按任意键继续向后执行
	system("pause");

	return 0;
};

执行结果 :

函数开始 : Tom
函数结束 : Aom
程序结束 : Aom
Press any key to continue . . .

在这里插入图片描述


4、特别注意 - 确保指针指向的空间可修改


使用 常量类型转换 const_cast 时 , 开发者必须确保 指针指向 的空间是可以修改的 , 如果不能修改 , 强行修改 , 会带来未知灾难性的后果 ;


如 : 定义了 字符串常量 , 字符串常量 不会分配内存 , 而是 存储在了 符号表 中 ;

	// 此处直接定义了一个常量字符串
	// 该常量字符串没有分配内存
	// 该常量存储在了 符号表 中
	const char * str = "Tom";

可参考 【C++】C 语言 和 C++ 语言中 const 关键字分析 ( const 关键字左数右指原则 | C 语言中常量的原理和缺陷 | C++ 语言中常量原理 - 符号表存储常量 ) 博客 , 在该博客中详细介绍了 C 语言常量 和 C++ 常量的原理 , C++ 中的常量都是存储在符号表中 , 符号表中的值肯定是不能被修改的 ;

使用 常量类型转换 const_cast , 强行将 符号表中的 常量 转为变量 , 但是 一旦执行 修改操作 , 直接在运行时报错 ;


错误代码示例 :

#include "iostream"
using namespace std;

// const char * p 表示修饰的数据是常量 , 数据不可更改
void fun(const char * str)
{
	cout << " 函数开始 : " << str << endl;

	// 直接修改 const char * p 的数据内容会报错
	// 报错 : error C3892: “p”: 不能给常量赋值
	//p[0] = 'A';

	char* tmp = const_cast<char*>(str);
	tmp[0] = 'A';

	cout << " 函数结束 : " << str << endl;
}

int main() {

	// 此处直接定义了一个常量字符串
	// 该常量字符串没有分配内存
	// 该常量存储在了 符号表 中
	const char * str = "Tom";
	fun(str);

	cout << " 程序结束 : " << str << endl;


	// 控制台暂停 , 按任意键继续向后执行
	system("pause");

	return 0;
};

执行结果 : 修改 符号表常量 的那一行代码 , 引发了未知异常 ;

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vs2019 - MFC对话框程序的工程名称不支持下划线命名法

文章目录 vs2019 - MFC对话框程序的工程名称不支持下划线命名法概述笔记备注END vs2019 - MFC对话框程序的工程名称不支持下划线命名法 概述 正在写账单分析程序, 用MFC 对话框. 因为比较习惯下划线命名法, 就在向导中给工程名称起了一个my_test这样的名称(下划线命名法, 小…

SpringBoot自动配置注入Bean工具autoconfigure

依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency> yml配置 student:red: com.ma.config.MinIOConfigProperties spring.factories org.springframework.…

LeetCode Hot100 42.接雨水

题目&#xff1a; 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 方法一&#xff08;相向双指针&#xff09;&#xff1a;竖着计算面积 代码&#xff1a; class Solution {public int trap(int[] he…

Taro3+Vue3重构Mpvue小程序项目踩坑记

1、Taro小程序编译时报错&#xff1b; 原因:页面中存在小程序识别不了的标签&#xff1b;如div解决方法&#xff1a; 将div标签替换成小程序可识别的标签&#xff1b; 安装Taro中提供的插件:tarojs/plugin-html, 使其可被识别&#xff1b; 插件安装教程参考Taro官网&#xff1…

Flink Flink中的合流

一、Flink中的基本合流操作 在实际应用中&#xff0c;我们经常会遇到来源不同的多条流&#xff0c;需要将它们的数据进行联合处理。所以 Flink 中合流的操作会更加普遍&#xff0c;对应的 API 也更加丰富。 二、联合&#xff08;Union&#xff09; 最简单的合流操作&#xf…

「我在淘天做技术」迈步从头越 - 阿里妈妈广告智能决策技术的演进之路

作者&#xff1a;妙临、霁光、玺羽 一、前言 在线广告对于大多数同学来说是一个既熟悉又陌生的技术领域。「搜广推」、「搜推广」等各种组合耳熟能详&#xff0c;但广告和搜索推荐有本质区别&#xff1a;广告解决的是“媒体-广告平台-广告主”等多方优化问题&#xff0c;其中媒…

手机便签app哪个比较好用?

手机便签类软件的种类是比较多的&#xff0c;不管是安卓手机品牌还是苹果手机品牌的手机&#xff0c;在手机的应用商店中搜索“便签”&#xff0c;大家会找到很多便签类软件。那么&#xff0c;手机便签APP哪个比较好用呢&#xff1f; 在选择手机便签APP时&#xff0c;大家比较…

详解原生Spring中的控制反转和依赖注入-构造注入和Set注入

&#x1f609;&#x1f609; 学习交流群&#xff1a; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 &#x1f96d;&#x1f96d;3&#xff1a;QQ群&#xff1a;583783…

Java变量理解

成员变量VS局部变量的区别 语法形式&#xff1a;从语法形式上看&#xff0c;成员变量是属于类的&#xff0c;而局部变量是在代码块或方法中定义的变量或是方法的参数&#xff1b;成员变量可以被 public,private,static 等修饰符所修饰&#xff0c;而局部变量不能被访问控制修饰…

如何高效批量生成条形码?

条形码作为商品、库存和信息管理的基础工具&#xff0c;扮演着至关重要的角色。为了满足用户对于高效、专业、多样化的条形码生成需求&#xff0c;我们推出了一款专业高效的在线条形码生成工具。 网址&#xff1a;https://www.1txm.com/ 多样化条形码支持 易条形支持多种常见…

【算法萌新闯力扣】:旋转链表

力扣题目&#xff1a;旋转链表 开篇 今天是备战蓝桥杯的第25天和算法村开营第3天&#xff01;经过这3天的学习&#xff0c;感觉自己对链表的掌握程度大大地提升&#xff0c;尤其是在帮村里的同学讨论相关问题时。本篇文章&#xff0c;给大家带来一道旋转链表的题目&#xff0c…

leetcode:用队列实现栈(后进先出)

题目描述 题目链接&#xff1a;225. 用队列实现栈 - 力扣&#xff08;LeetCode&#xff09; 题目分析 我们先把之前写的队列实现代码搬过来 用队列实现栈最主要的是实现栈后进先出的特点&#xff0c;而队列的特点是先进先出&#xff0c;那么我们可以用两个队列来实现 一个队…

PTA-6-48 使用面向对象的思想编写程序描述动物

题目&#xff1a; 使用面向对象的思想编写程序描述动物&#xff0c;说明&#xff1a; &#xff08;1) 分析兔子和青蛙的共性&#xff0c;定义抽象的动物类&#xff0c;拥有一些动物共有的属性&#xff1a;名字、颜色、类别&#xff08;哺乳类、非哺乳类&#xff09;&#xff0c…

Redis 事件轮询

1 Redis 为什么快 数据存在内存中, 直接操作内存中的数据单线程处理业务请求避免了多线的上下文切换, 锁竞争等弊端使用 IO 多路复用支撑更高的网络请求使用事件驱动模型, 通过事件通知模式, 减少不必要的等待… 这些都是 Redis 快的原因。 但是这些到了代码层面是如何实现的呢…

出纳常用的月报表,熬夜做了这8份直接用!

做出纳&#xff0c;公司财务的日报表是必不可少的&#xff0c;收支了多少&#xff0c;支出了多少&#xff0c;这些都是要记录下来的&#xff01; 一份出纳日报表通常包含以下内容&#xff1a; 1. 日期&#xff1a;报告涵盖的具体日期&#xff0c;标明是哪一天的财务数据。 2. 收…

【论文阅读】An Experimental Survey of Missing Data Imputation Algorithms

论文地址&#xff1a;An Experimental Survey of Missing Data Imputation Algorithms | IEEE Journals & Magazine | IEEE Xplore 处理缺失数据最简单的方法就是是丢弃缺失值的样本&#xff0c;但这会使得数据更加不完整并且导致偏差或影响结果的代表性。因此&#xff0c;…

bash编程 数组和for循环的应用

bash编程 数组和for循环的应用 1、问题背景2、bash 定义数组3、for循环遍历输出数组所有元素4、编写bash脚本输出每个端口是否在监听状态 1、问题背景 linux服务器开机后&#xff0c;需要检查一组端口是否在监听&#xff0c;以便判断这些端口对应的服务是否在运行。可以考虑使…

别再让假的fiddler教程毒害你了,来看这套最全最新的fiddler全工具讲解

fiddler界面工具栏介绍 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; &#xff08;1&#xff09;WinConfig&#xff1a;windows 使用了一种叫做“AppContainer”的隔离技术&#xff0c;使得一些流量无法正常捕获&#xff0c;在 fiddler中点击 WinConfig…

轻巧高效的剃须好工具,DOCO黑刃电动剃须刀上手

剃须刀大家都用过&#xff0c;我比较喜欢电动剃须刀&#xff0c;尤其是多刀头的悬浮剃须刀&#xff0c;感觉用起来很方便&#xff0c;剃须效率也很高。最近我在用一款DOCO小蔻的黑刃电动剃须刀&#xff0c;这款剃须刀轻巧易用&#xff0c;而且性价比超高。 相比于同类产品&…

深度盘点:100 个 Python 数据分析函数总结

经过一段时间的整理&#xff0c;本期将分享我认为比较常用的100个实用函数&#xff0c;这些函数大致可以分为六类&#xff0c;分别是统计汇总函数、数据清洗函数、数据筛选、绘图与元素级运算函数、时间序列函数和其他函数。 技术交流 技术要学会交流、分享&#xff0c;不建议…