0
点赞
收藏
分享

微信扫一扫

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

分湖芝蘭 2022-03-10 阅读 122
c++

🌏目录


🤔 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对引用有如下补充介绍

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

👇例子说明

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对指针有如下介绍

指向常量的引用类似,我们同样无法通过这种特殊指针来修改其所指向的对象的值,因此也是一个底层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 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】的影响,只要满足等号右边【表达式可以经过类型转换】成为左边对象的类型,拷贝就可以进行👇

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

举报

相关推荐

0 条评论