【C++】指向常量的引用/指针、常量指针、顶层底层const的分析

📣🥳🥳🥳📣

✨Hello! 如果这篇【文章】对你有帮助😄,希望可以给博主点个赞👍鼓励一下😘

📣🥳🥳🥳📣



🤔 1.指向常量的引用

🏷️ 场景需求

👇 先来看看这样一个场景需求👇

▶️ 程序里有一个对象r(C++里对象即变量,可以理解为同义词),现在我想设置一个【引用】【绑定】它,但有一个要求:不能【通过这个引用】【修改】这个对象的值,但允许通过这个引用来【读取】这个对象。

📝 对于这个场景,C++11标准下这样来实现

int r = 1;
const int &R = r;  //引用R绑定了r
cout << R;  //正确:允许通过引用R读取r的值
R = 2;      //错误:终端提示“ assignment of read-only reference 'R' ”

这个特殊的引用R应该叫个什么拉风的名字(术语)比较好呢?

✅ 《C++ primer 5th》称其指向常量的引用(reference to const),又称常量引用

🌟🌟顺便把【电子版】给到大家,有需要的可以在文章最下面拿🌟🌟

在这里插入图片描述

🏷️ 具体分析

上述代码中const int &R = r的图解如下👇

在这里插入图片描述

👇 第五版中文版P55对引用有如下补充介绍

引用的类型必须与其所引用对象的类型一致,但是有两种例外。第一种例外情况就是在初始化常量引用指向常量的引用)时允许【用任意表达式作为初始值】,只要【该表达式的结果】【类型转换】(P32节2.1.2)成【引用的类型】即可。

可能有人会问第二种例外情况是什么,我也想知道,但书上作者好像没写🤣,如果有人知道可以在评论区里分享一下。谢谢啦!

👇例子说明

const int m = 1;
int &M = m;         //错误:普通的int&不能绑定到int整型常量上(反证法:如果可以,那通过M就能修改m的值,这样就和m是常量的规定发生冲突)
int r = 2;
const int &R = r;   //这就是上面的例子。等号右侧的表达式`r`其类型是`int整型`,可以转换成`int整型常量`,因此不会报错
const int &x = 10;  //等号右侧的表达式`10`其类型为`整型字面值常量`,可以转换成`int整型常量`
const int &y = r*2+3;  //等号右侧表达式的计算结果同样为`整型字面值常量`

此外,对于下面这种情况,仍然成立

double pi = 3.14;
const int &PI = pi;  

右侧表达式pi的类型为double类型,可以经类型转换成为int整型常量。那这样的话PIpi的值不就不同了吗?没错,这二者的值确实不同,打印发现pi为3.14,PI为3。这和一个新概念有关——临时量(temporary)对象,简称临时量。图解如下👇

在这里插入图片描述
📌 最后,在分析概念指向常量的指针之前,补充两概念——底层const&顶层const
底层const的定义:若【通过】【指针/引用】无法对所【指向/绑定】的对象进行【值修改】,我们就称该【指针/引用】为一个底层const

因此上面所有例子中的 `指向常量的指针` 都是 `底层const`

顶层const的定义:若对象【自身是一个常量】,不可变,则自身就是顶层const

const int x = 1;  //x就是一个顶层const

🤔 2.指向常量的指针

🏷️ 场景需求

👇 同样来看看这样一个场景需求👇

▶️ 程序里有一个对象r,现在我想设置一个【指针】【指向】它,但有一个要求:不能【通过这个指针】【修改】这个对象的值,但允许通过这个指针来【读取】这个对象。

📝 对于这个场景,C++11标准下这样来实现

int r = 1;
const int *p = &r;  //指针p指向了r
cout << *p;  //正确:允许通过指针p读取r的值
*p = 2;      //错误:终端提示“ assignment of read-only location '* p' ”

这个特殊的指针p应该叫个什么拉风的名字(术语)比较好呢?

✅ 《C++ primer 5th》称其指向常量的指针(pointer to const)。但与前面介绍指向常量的引用不同的是,指向常量的指针不能称为常量指针常量指针是另外一个术语的名字。

🏷️ 具体分析

上述代码中const int &p = &r的图解如下👇

在这里插入图片描述

👇 第五版中文版P56对指针有如下介绍

指针的类型必须与其所指对象的类型一致,例如,int类型指针必须指向int类型。但是有两种例外。第一种例外情况是允许令一个指向常量的指针指向一个【非常量对象】,没有规定指向常量的指针其必须要指向一个常量

指向常量的引用类似,我们同样无法通过这种特殊指针来修改其所指向的对象的值,因此也是一个底层const

👇例子说明

const int r = 1;
int R = 10;
const int *p = &r;  //正确:r是一个常量,`指向常量的指针` 理应可以指向一个 `常量`
const int *p1 = &R;  //正确:r是一个非常亮,但 `指向常量的指针` 可以指向一个 `非常量对象`
const int *p2 = 10;  //错误:没有允许 `指向常量的指针` 可以指向一个 `字面值常量`

🤔 3.常量指针

🏷️ 场景需求

👇 看看这样一个场景需求👇

▶️ 程序里有一个对象r,现在我想设置一个【指针/引用】【指向/绑定】它,但有一个要求:可以【通过这个指针/引用】【读取和修改】这个对象的值,但不允许这个指针/引用【移情别恋】其它对象。这里解释下“移情别恋”,对于指针p,要求它不能再更改指向,即不能再指向其它对象;而对于引用R,要求它不能再更改绑定,即不能再绑定其他对象【然而这本身就是引用的默认要求!可以见另一篇文章【C++】为何引入“引用“? 指针和引用有何区别?,因此这个并不算特殊的引用,这就是基本的引用。所以下面重点考虑这个特殊指针的语法】。

📝 对于这个场景,C++11标准下这样来实现

int x = 1, y = 10;
int *const p = &x;  //指针p指向了x
*p = 2;     //正确:允许通过指针p读取和修改x的值
p = &y;     //错误:终端提示“ assignment of read-only variable 'p' ”

这个特殊的变量p应该叫个什么拉风的名字(术语)比较好呢?

✅ 《C++ primer 5th》称其常量指针(const pointer)

🏷️ 具体分析

上述代码中int *const p = &x的图解如下👇

在这里插入图片描述

👇 弄清楚下面这些声明的含义

int x = 1;
int *const p = &x;
const int y = 1;
const int *const pp = &y;

“当声明符较多时最行之有效的办法就是从右往左阅读。”

1️⃣ 对于int *const p,首先是const,说明p自身是一个常量,然后是*,说明p是一个指针,最后是int,说明p是一个指向int整型常量指针,因此等号右侧理应是一个int整型对象的地址,合理。
2️⃣ 对于const int *const pp,首先是const,说明pp自身是一个常量,然后是*,说明pp是一个指针,然后是int,说明pp是一个指向int整型常量指针,最后是const,说明pp是一个指向int整型常量常量指针,因此等号右侧是一个int整型常量,合理。

📌 根据前面对顶层const底层const的定义,最后还需补充的是
1️⃣ int *const p是一个顶层const
2️⃣ const int *const pp既是一个顶层const也是一个底层const


🤔 4.顶层const和底层const的内容补充

“【顶层const】可以表示任意的对象是常量,这一点对任何数据类型都适用,如算术类型、类、指针等。【底层const】则与指针和引用等复合类型的基本类型部分有关。比较特殊的是,指针类型既可以是顶层const也可以是底层const,这一点和其他类型相比区别明显。”

const int x = 0;    //对象x自身无法修改,这是一个顶层const
int r = 0;
int *const p = &r;  //指向r的常量指针,自身指向不能再修改,这是一个顶层const
const int *p1 = &r; //p1是一个指向常量的指针,无法通过p修改r,这是一个底层const
const int &R = r;   //R是一个指向常量的引用,无法通过R修改r,这是一个底层const
const int *const p2 = &x;  //p2是一个指向常量的常量指针,顶层const+底层const

🏷️ 拷贝操作

“当执行对象之间的【拷贝操作】时,【顶层const不受什么影响】,有没有都一样,可以忽视,但【底层const的限制不能忽视】。要确保拷入和拷出的对象必须具有相同的底层const资格】,或者等号右边【表达式可以经过类型转换】成为左边对象的类型。”

也就是说:【忽略顶层const】的影响,只要满足等号右边【表达式可以经过类型转换】成为左边对象的类型,拷贝就可以进行👇

//在上面一份代码的基础上
int *p3 = p2;  //错误:忽略顶层const,p2是一个const int*类型,p3是一个int *类型,无法类型转换
p1 = p2;       //正确:忽略顶层const,p1和p2都是const int*类型
p1 = &r;       //正确:右边为int *类型,左边为const int*类型,可以类型转换   

👇【C++ primer 5th】和【C++ primer plus 6th】中文版,分享自用👇

在这里插入图片描述
primer和plus的区别简单说plus更小白更基础一些,根据自身情况选择。百度网盘的外链可能不让放,直接底下评论或私信就行。


✨如有问题欢迎在底下评论留言或私信!

如果这篇【文章】对你有帮助😄,希望可以给博主【点个赞👍】鼓励一下😘

❤️Thanks for your encouragement❤️

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

John Chen1223

点赞是美意!打赏是鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值