C++ Const 用法汇总
最开始只是用 const 来定义常量,学到了指针传参的时候又知道了用 const 来防止一些值的修改,学到类的时候又看到非静态成员函数后边加个 const 来干嘛干嘛,然后么又听说什么顶层 const、底层 const... 真是越学越迷糊了,赶紧做一波整理。
[2023 年 3 月 24 日更新:] 此文章已经重写,请查看:_The const and constexpr in C++ (REMAKE)_
最基本的用法 —— 定义常量
这个不必多说,直接上代码:
1 | int a = 1; |
除了这个,还有一点是,虽然似乎我们可以通过一些 “骚操作” 改变 const 修饰的变量(常量?)的值,但是输出的时候,会发现结果并没有改变。看下边的代码:
1 |
|
但是如果加上 volatile
关键词,却可以发现结果也可以跟着变:
1 |
|
但是,上边的 const
修饰的都不是全局变量。如果修饰的是全局变量,我们似乎就不能通过指针的小把戏来改变 const
的值了:
1 | // 错误代码: |
但如果加上了 volatile
依然可以跑,并且也可以用指针来修改它的值:
1 |
|
总结一下,就是 ——
- 如果是局部的
const
,那至少有两方面的保护:一是编译检查,看看我们下边的代码是否显而易见地尝试去改变它的值,如果有那就报错;二是编译器的自动优化,编译器会把这个变量的值复制一份放到寄存器里,所以即使我们用指针改变了原来内存里的值,输出的结果还是原来的值(备份到寄存器的原来的值的拷贝),所以当我们使用voliatile
关键字关闭了编译器的这种优化,让程序每运行到要用到这个const
修饰的变量的时候都去原来的地址读取值的时候,我们的小把戏成功了。 - 如果是全局的
const
,还会有其他的机制,具体还没弄清楚,不过你可以看看《Linux 系统编程学习总结 (二)ELF - 知乎》这篇文章,也许会有帮助?
顶层 const 和底层 const
首先,讨论顶层底层的 const,一般都是对指针变量才有意义。那么啥是顶层 const?啥是底层 const?
顶层 const(top-level const)表示指针本身是个常量;
底层 const(low-level const)表示指针所指的对象是一个常量。
举几个例子:
1 | int x = 7; |
也就是说:
- 仅仅被顶层 const 修饰,意味着指针变量的指向无法改变,但可以操作指向的值(指针常量?指针(地址)是个常量);
- 仅仅被底层 const 修饰,意味着指针变量的指向可以改变,但无法操作指向的值(常量指针? 指向常量的指针);
- 如果两重修饰,那么就就没办法改变指针的指向,也没办法操作指向的值。
顺便一说对于引用的情况。因为引用必须初始化并且初始化完成后(起玩别名后就不能改变它引用的对象了),所以 const int &
就是顶层的,并且没有 int & const
这种写法。
函数中的 const
参数列表中的 const
其实就是希望函数运行过程中不改变这个变量的值。比如写函数原型的时候用 const int &
,其中 const
表示这个函数对这个变量的操作是只读的,不会改变原来的值,而 &
的作用就是,既然这里只是要读一读这个变量的值,并不对它进行操作,那我就不创建副本了,直接用它自己。
返回的 const
这边还没弄清楚,以后弄清楚了再写。
类的非静态成员函数后边跟的 const
这样可以让这个函数的 this
是只读的。
看这篇文章:《C\C++ 中函数后面加 const_51CTO 博客_c++ const 函数》
非静态成员函数后面加 const(加到非成员函数或静态成员后面会产生编译错误)表示成员函数隐含传入的 this 指针为 const 指针,决定了在该成员函数中, 任意修改它所在的类的成员的操作都是不允许的(因为隐含了对 this 指针的 const 引用)
唯一的例外是对于 mutable 修饰的成员。加了 const 的成员函数,可以被非 const 对象和 const 对象调用,但不加 const 的成员函数 只能被非 const 对象调用。