常量const、引用、指针的大杂烩

news2024/11/28 8:42:15

文章目录

  • 1 普通引用
    • 1.1 对普通值的普通引用
    • 1.2 对常量值的普通引用
    • 1.3 对普通指针的普通引用
    • 1.4 对常量指针的普通引用
    • 1.5 对指针常量的普通引用
    • 1.6 对指向常量的指针常量的普通引用
  • 2 常量引用
    • 2.1 对普通值的常量引用
    • 2.2 对常量值的常量引用
    • 2.3 对普通指针的常量引用
    • 2.4 对常量指针的常量引用
    • 2.5 对指针常量的常量引用
    • 2.6 对指向常量的指针常量的常量引用
  • 3 总结

这标题,是不是听着就头大?常量(const)、引用、指针本来就 C++ 里面三个很头疼的概念,现在把他们合到一起,更想不明白了。没关系,看完本文后,你一定会对这三个概念有更清晰的认识。

首先我们分析分析,这三个合到一起,共能产生多少种不同的组合?一个对象可以是非指针类型(姑且称为一个“值”),也可以是指针类型。其中值可以是普通值,也可以是常量值;指针可以是普通指针、常量指针(指向常量,指针本身可变),指针常量(指针不可变,指向的值可变)、指向常量的指针常量(指针和指向的值都不可变)。所以一个对象可以细分为6种。而引用也有两种,一种是普通引用,一种是常量引用。这样算下来,应该是 6 × 2 = 12 6\times2=12 6×2=12 种组合了。其中标题“常量引用绑定到指向常量的常量指针”是最复杂的组合。下面我们就逐个讲清楚这些组合,如何定义,有哪些特点。

为不失严谨性,作出以下两点说明:

  • 有人说多于12种组合,因为指针可以指向另一个指针,引用也分左值引用和右值引用。没错,但我们这里不考虑多级指针,并只考虑左值引用。

  • 有人说少于12种组合,因为一些组合并不合法,无法定义。也没错,但我们不妨称之为“非法组合”。

1 普通引用

1.1 对普通值的普通引用

int i = 1;
int &ri = i;

这是最简单的。ri 就是对普通值 i 的一个普通引用。ri 可以看作 i 的一个别名:我们给函数传 ri 就是在传 i ,修改 ri 的值就是在修改 i 的值。

1.2 对常量值的普通引用

const int ci = 1;
int &rci = ci; // 非法

这是非法的。我们不能把一个常值绑到一个非常量引用上。理由是,如果可以绑定,则可以通过 rci 修改 ci ,而 ci 是常值,这不就矛盾了吗。因此 C++ 规定其为非法。

1.3 对普通指针的普通引用

int i = 1;
int *p = &i;
int *&rp = p;

这是第一个复合类型。怎么理解 rp 的类型名很关键。我们按照由内向外做如下解读:

rp 也是 p 的别名,用 rp 时就是在用 p 。例如通过 rp 可修改 i 的值。

*rp = 10;
std::cout << i << '\n'; // 输出10

1.4 对常量指针的普通引用

int i = 1;
const int *cp = &i;
const int *&rcp = cp;

这次类型名解读和1.3节中的类似,唯一区别是这次指针指向一个 const int 对象。正是这一区别,是我们无法通过 rcp 改变 i 的值了,正如无法通过 cp 改变 i 的值一样。

值得一提的是,因为此例中 i 不是 const int ,所以我们仍然可以改变 i 的值,此时 *cp*rcp 的值也随之变化。

i = 2;
cout << *cp << ' ' << *rcp << '\n'; // 输出2 2

所谓常量指针指向一个常量,仅是指针认为它指向常量,至于实际到底指向什么,常量还是非常量都是可以的。我们称之为指针被欺骗(见2.1节)。如果我们把一开始就把 i 定义成 const int 类型的,就使 cp 变成指向一个真正的常量的指针了。

1.5 对指针常量的普通引用

int i = 1;
int *const pc = &i;
int *&rpc = pc; // 非法

这是第二个非法组合。原因类似,因为指针常量 pc 是顶层 const,我们无法把一个普通的引用绑定到顶层 const上,否则就能通过 rpc 修改一个常量 pc 了,矛盾了。

1.6 对指向常量的指针常量的普通引用

int i = 1;
const int *const cpc = &i;
const int *&rcpc = cpc; // 非法

这是第三个非法组合,原因同上。

普通引用的六种组合到这里就讲完了,总结一下,非法的三种组合都是自己本身就是常量的,而普通引用禁止绑定到常量上,常量只能被常量引用绑定。这就来到下一节了:常量引用。

2 常量引用

2.1 对普通值的常量引用

int i = 1;
const int &cri = i;

把常量引用绑定到普通值上,就好比让常量指针指向一个非常量,都是虚假的绑定/指向,我们可以戏称之为:引用/指针被欺骗了。这里常量引用以为自己绑到了常量上,所以拒绝通过 cri 来修改 i;但是实际上 i 不是常量,所以可以通过 i 自己修改 i 的,此时 cri 的值也跟着变。

i = 3;
std::cout << cri << '\n'; // 输出3

2.2 对常量值的常量引用

const int ci = 1;
const int &crci = ci;

这才是真正的绑到一个常量上了。这儿我问大家一个问题:对“常量”值进行“常量”引用的时候,明明有两处“常量”,可为什么语句里面只看到一个 const 关键字?可能懂的人觉得这问题很stupid,但是在写一些复杂的声明的时候,真有可能犯迷糊。提示:看看1.2节,对普通值进行常量引用时,语句里有几个 const 关键字?再看看2.1节,对普通值常量引用的语句和本节的声明引用的语句有何不同?

2.3 对普通指针的常量引用

int i = 1;
int *p = &i;
int *const &crp = p;

这个声明引用的语句也有点意思,我们解读一下。

可以看到,这也是个被欺骗的引用。我们不能改 crp 的值,因为它以为自己绑的是常量,不过,它以为它以为的就是它以为的?我们还是可以改 p,此时 crp 跟着变。另一方面,虽然我们不能改 crp ,但我们可以改 *crp,因为 crp 指向一个普通的 int 变量。

*crp = 9;
cout << i << '\n'; // 输出9
crp = nullptr; // 非法
p = nullptr; // 合法,p和crp都变成空指针

2.4 对常量指针的常量引用

int i = 1;
const int *cp = &i;
const int *const &crcp = cp;

这个声明和2.3的基本相似,唯一区别在于指针指向的是一个 const int 对象。造成的影响就是不能再改 *crcp 了,但 crcp 仍是被欺骗的引用,因为它绑的是底层 const,而非顶层 const。

*crcp = 9; // 非法
crcp = nullptr; // 非法
cp = nullptr; // 合法,cp和crcp都变成空指针

2.5 对指针常量的常量引用

int i = 1;
int *const pc = &i;
int *const &crpc = pc;

这个引用的声明和2.3节非常像,大家要注意区分,还是思考那个问题,为什么对指针“常量”进行“常量”引用,只出现一个 const

我们不能修改 crpc,也不能修改 pc 。我们可以修改的是 *crpc,用它来修改 i 是可以的。

*crpc = 3;
cout << i << '\n'; // 输出3

2.6 对指向常量的指针常量的常量引用

他来了他来了,最复杂的它终于来了!

int i = 1;
const int* const cpc = &i;
const int* const &crcpc = cpc;

以上是对声明引用的解读,有了这个解读,是不是就清晰多了。从这么多常量就可以看出来了,它自己不能、也不能通过它进行任何形式的修改。

3 总结

普通引用常量引用
普通值int &ri = i;const int &cri = i;
常量值int &rci = ci; 非法const int &crci = ci;
普通指针int *&rp = p; 可以通过 rp 修改原值,可以修改 rpint *const &crp = p; 可以通过 crp 修改原值,不能修改 crp
常量指针const int *&rcp = cp; 无法通过 rcp 修改原值,可以修改 rcpconst int *const &crcp = cp; 不能通过 crcp 修改原值,不能修改 crcp
指针常量int *&rpc = pc; 非法int *const &crpc = pc; 可以通过 crpc 修改原值,不能修改 crpc
指向常量的指针常量const int *&rcpc = cpc; 非法const int* const &crcpc = cpc; 不可以通过 crcpc 修改原值,不能修改 crcpc

完结撒花~

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

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

相关文章

2023年留学基金委(CSC)西部/地方合作项目选派办法及解读

2023年2月13日国家留学基金委&#xff08;CSC&#xff09;官方网站发布了2023年西部地区人才培养特别项目、地方合作项目通知。知识人网小编现将其选派工作流程及选派办法原文转载并加以解读、提出建议。知识人网建议1. 邀请函是公派申请的必备条件。对于外语语言证明未达标者&…

React学习笔记(番外二)——列表多选批量处理复合组件

React学习笔记&#xff08;番外二&#xff09;——列表多选批量操作复合组件前言〇、Show you the code一、 任务分析及拆解表头行的Checkbox——总开关记录行的Checkbox——行级开关二、 基础实现表头行的文件——header-row.js记录行的文件——record-row.js页面的文件App.js…

Linux操作系统学习(进程退出)

文章目录进程终止退出码进程退出场景进程退出的方式进程终止 退出码 ​ 我们知道每个main函数结尾都有return&#xff0c;一般都是return 0&#xff0c;用echo $&#xff1f;就可以查看它的退出码&#xff0c;0就是他的退出码&#xff0c;也可以写一些别的数值&#xff0c;比…

微服务项目【网关服务限流熔断降级分布式事务】

网关服务限流熔断降级 第1步&#xff1a;启动sentinel-dashboard控制台和Nacos注册中心服务 第2步&#xff1a;在网关服务中引入sentinel依赖 <!-- sentinel --> <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-…

好好学react源码然后惊艳所有人

hello&#xff0c;这里是潇晨&#xff0c;今天我们来聊聊react源码&#xff0c;作为使用react多年的前端工程师&#xff0c;我们是否还在使用着各种应用层面的库、框架呢&#xff0c;是否在面试过程中遇到一些关于react源码方面的问题呢&#xff0c;如果是&#xff0c;那么是否…

数据结构与算法:java对象的比较

1.基本类型的比较 在Java中&#xff0c;基本类型的对象可以直接比较大小。 public class TestCompare {public static void main(String[] args) {int a 10;int b 20;System.out.println(a > b);System.out.println(a < b);System.out.println(a b);char c1 A;char…

互联网舆情监测公司监测哪些内容,TOOM北京舆情监测公司

互联网舆情监测公司是一种提供舆情监测、分析和管理服务的公司&#xff0c;其业务主要涉及互联网舆情监测、数据分析、报告撰写、危机处理等方面。这些公司通过使用各种技术和工具&#xff0c;帮助客户监测他们在互联网上的声誉和品牌形象&#xff0c;并提供相应的建议和解决方…

前端基于 Docker 的 SSR 持续开发集成环境实践

项目收益 整体开发效率提升20%。加快首屏渲染速度&#xff0c;减少白屏时间&#xff0c;弱网环境下页面打开速度提升40%。 权衡 在选择使用SSR之前&#xff0c;需要考虑以下事项&#xff01; SSR需要可以运行Node.js的服务器&#xff0c;学习成本相对较高。对于服务器而言&a…

“就业”or“创业”,大学生毕业如何选择,校园市场是新出路?

据公开数据显示&#xff0c;2023届全国高校毕业生预计达到1158万人&#xff0c;同比增加82万人。规模和增量创历史新高。今年就业形势再次复杂严峻起来。 “就业难”这个词在疫情下的毕业季尤为明显。超过1000万人同时加入了争夺就业机会的行列&#xff0c;形成了庞大的求职阵容…

网络安全-靶场搭建

网络安全-靶场搭建 靶场就是给你练习用的&#xff0c;因为如果你直接用其他网站搞会把他搞炸的&#xff08;犯法的&#xff09; 简单概括&#xff1a;把靶场文件放到Phpstudy的网站&#xff0c;放到根目录里面 要用到之前下载的phpstudy 然后开启mysql和apache&#xff0c;默…

【2023】Prometheus-Blackbox_exporter使用

目录1.下载及安装blackbox_exporter2.修改配置文件设置监控内容2.1.使用http方式作为探测3.与prometheus集成4.导入blackbox仪表盘进行观测1.下载及安装blackbox_exporter 下载安装包 wget https://github.com/prometheus/blackbox_exporter/releases/download/v0.23.0/black…

企业现代化管理模式中,数据指标体系是什么

当前时代&#xff0c;数据已经成为了构建现代社会的重要元素&#xff0c;渗透到人们生活的方方面面。在商业世界中&#xff0c;数据的传播应用更是按下了加速键&#xff0c;在短时间内就让各行各业的企业开始围绕数据进行信息化、数字化转型&#xff0c;把数据当作企业重要的战…

前端原生 CSS 跑马灯效果,无限轮播(横竖版本,带渐变遮罩,简单实用)

一、横版跑马灯 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-wid…

Redis入门到实战-数据结构 (四、原理篇)

一、动态字符串SDS 我们都知道Redis中保存的Key是字符串&#xff0c;value往往是字符串或者字符串的集合。可见字符串是Redis中最常用的一种数据结构。 不过Redis没有直接使用C语言中的字符串&#xff0c;因为C语言字符串存在很多问题&#xff1a; 获取字符串长度的需要通过…

计算机网络之http07 http2,http3

HTTP1.2 http1.2都做了哪些优化 (1)头部压缩 使用HPACK压缩头部 头部冗长&#xff0c;大量重复字段 &#xff08;2&#xff09;二进制帧 将报文头部和内容字符编码改为二进制格式 字符编码未压缩 &#xff08;3&#xff09;并发传输 解决h1.1 队头阻塞问题&#xff0c;多车道 …

opencv通道的分离与合并

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主lqj_本人擅长微信小程序,前端,python,等方面的知识https://blog.csdn.net/lbcyllqj?spm1011.2415.3001.5343哔哩哔哩欢迎关注…

腾讯云 cos 字体在CDN上跨域处理

问题描述&#xff1a;项目中用到了字体的静态资源&#xff0c;把静态资源放到了腾讯云对象存储提供的 COS 上&#xff0c;同时启用它的CDN来加速。但是&#xff0c;调试的过程中发现报错&#xff1a;CSS加载字体跨域了&#xff0c;字体图标无法正常显示。 原因&#xff1a;字体…

torch.grid_sample

参考&#xff1a; 双线性插值的理论Pytorch grid_sample解析PyTorch中grid_sample的使用方法pytorch中的grid_sample()使用 查阅官方文档&#xff0c;TORCH.NN.FUNCTIONAL.GRID_SAMPLE grid_sample的函数签名如下所示&#xff0c;torch.nn.functional.grid_sample(input, gr…

Java设计模式总叙

文章目录基本概念设计模式的七大原则设计模式有哪些高频使用&经典的设计模式创建型-工厂方法模式创建型-建造者模式结构型-代理模式结构型-外观模式行为型-策略模式行为型-模板方法补充UML类图关系参考基本概念 使得代码编写真正工程化&#xff0c;它是软件工程的基石。 …

【cuda入门系列】通过代码真实打印线程ID

【cuda入门系列】通过代码真实打印线程ID1.gridDim(6,1),blockDim(4,1)2.gridDim(3,2),blockDim(2,2)【cuda入门系列之参加CUDA线上训练营】在Jetson nano本地跑 hello cuda&#xff01; 【cuda入门系列之参加CUDA线上训练营】一文认识cuda基本概念 【cuda入门系列之参加CUDA线…