彻底搞懂 C++ 中 顶层 const 和 底层 const

本文详细解析了C++中顶层const和底层const的区别,包括它们的概念、示例、与指针和引用的关系,以及类型转换规则。通过实例演示和公式解释,帮助读者掌握这两者在实际编程中的使用和限制。
摘要由CSDN通过智能技术生成

写在前面

最近在项目中使用 const 关键字 时遇到了一些困惑, 重新琢磨了一下 C++ 中 const 关键字的使用,对于顶层 const 和 底层 const 重新学习后又有了一点新的理解,在此记录一下。

顶层 const 与 底层 const

概念

  • 顶层 const:可以修饰所有数据类型,表示该类型的对象本身是常量
  • 底层 const:与指针和引用类型有关,表示地址所指向的对象是常量

示例

int i = 10;
const int ii = 11; // 顶层const: 对象 ii 本身是常量
const int *a = &i; // 底层const: 指针对象 a 本身不是常量,而所存地址指向的对象是常量
int const *b = &i; // 底层const: 与上一条语句写法不同,但都是表示指向常量的指针,即指针常量
int* const c = &i; // 顶层const: 指针对象 c 本身是常量,即常量指针
const int* const d = &i; // 左侧const是底层const,右侧const是顶层const
const int& e = i; // 底层const: 引用所存地址指向的对象是常量

我相信首次尝试理解 顶层 const 和 底层 const 概念的同学 看了上述的例子对于如何区分二者可能已经有点感觉了,但针对一些细节可能还存在一些疑惑,接下来我会针对一些关键点展开讲讲。
上述程序可访问 godbolt 执行测试

常量指针 与 指针常量

第一个问题我们来讲讲 常量指针、指针常量顶层 const、底层 const 联系。

概念

  • 常量指针:即指针本身是常量,表示指针存储的地址不可被修改
  • 指针常量:即指向常量的指针,表示其所指向的对象不可被修改

对应关系

对比 顶层 const、底层 const概念,我们可以发现,在 const 修饰指针变量时:

顶层 const 等价于 常量指针
底层 const 等价于 指针常量

例子

int i = 10;
int* const a = &i; //底层 const => 指针常量
const int* b = &i; //顶层 const => 常量指针
const int* const c = &i; //指向常量对象的常量指针,既有底层 const 又有 顶层 const

方便记忆:
const 在 * 号 左侧的为 底层 const => 指针常量 => 指针存储的地址不可被修改
const 在 * 号 右侧的为 顶层 const => 常量指针 => 指针指向的对象不可被修改

引用 与 const

第二个问题我们来讲讲 引用 中 使用 const 关键字。

如果对引用陌生虽然不影响下文阅读但也建议去补习一下

语法

在引用中使用 const 关键字只能按照如下语法使用:

int i = 10;
const int& a = i; //底层const 引用所存地址指向的对象是常量

或许大家对其为什么是底层 const 会有所困惑,下面讲讲我的理解:

int i = 10;
const int& a = i; // const int& a => const (int* const) a

对于引用来说我们可以将其视为 常量指针,因此变量 a 实际上可以看做 int* const 类型的数据,再在其上使用 const 进行修饰即得到了 const int* const 数据类型,因此此新增的 const 为 底层 const

在使用中只需记住:引用中使用的 const 一定是底层 const

类型转换

上面讲了这么多可能觉得不算难理解,但不知道为什么要区分顶层 const 和 底层 const,那么接下来就来看看其实际用途,首先看一下下面的代码是否能编译通过

int i = 10;
const int ii = 11;

i = ii; // (1)

const int* a = &i; // (2)
const int* b = ⅈ // (3)

int* const c = &i; // (4)
int* const d = ⅈ // (5)

const int* const e = &i; // (6)
const int* const f = ⅈ // (7)

const int* g = c; // (8)
const int* h = e; // (9)

int* const j = a; // (10)
int* const k = e; // (11)

int* const l = c // (12)
int* m = c // (13) 

上述程序可访问 godbolt 执行测试

编译过后会发现 (5),(10),(11),无法编译通过,是不是很困惑,记住下面的公式

左值(无 const || 顶层 const) = 右值(无 const || 顶层 const) => 可转换
左值(底层 const) = 右值(无 const || 顶层 const || 底层 const) => 可转换
左值(无 const || 顶层 const) = 右值(底层 const) => 不可转换

接下来我们一行行分析一下上述代码验证一下上面公式的正确性:

int i = 10;
const int ii = 11;

i = ii; // (1) i 无 const, ii 有顶层 const, 可转换

const int* a = &i; // (2) &i 为 int*, a 有底层 const, &i 无 const, 可转换
const int* b = ⅈ // (3) &ii 为 const int*, b 有底层 const, &ii 有底层 const, 可转换

int* const c = &i; // (4) &i 为 int*, c 有顶层 const, &i 无 const, 可转换
int* const d = ⅈ // (5) &ii 为 const int*, d 有顶层 const, &ii 有底层 const, 不可以转换

const int* const e = &i; // (6) &i 为 int*, e 有底层 const, &i 无 const, 可转换
const int* const f = ⅈ // (7) &ii 为 const int*, f 有底层 const, &ii 有底层 const, 可转换

const int* g = c; // (8) g 有底层 const, c 有顶层 const, 可以转换
const int* h = e; // (9) h 有底层 const, e 有底层 const, 可以转换

int* const j = a; // (10) j 有顶层 const, a 有底层 const, 不可以转换
int* const k = e; // (11) k 有顶层 const, e 有底层 const, 不可以转换

int* const l = c // (12) l 有顶层 const, c 有顶层 const, 可以转换
int* m = c // (13) m 无 const, c 有顶层 const, 可以转换

写在最后

看到这里恭喜你对于 const 的理解与运用有上了一个台阶,上面的内容是我学习 const 的一个总结,里面包含了一些个人的理解,可能在某些部分有失偏颇,有问题欢迎私信或者评论区讨论。

  • 11
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

鞠杉

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值