【C++】const关键字详解 && volatile关键字了解

文章目录

  • 1.const修饰符的作用
  • 2.const常量的存储
  • 3.const修饰变量
  • 4.const修饰指针 && 引用
    • 4.1修饰指针
    • 4.2修饰引用
    • 4.3指针与引用的联系
  • 5.const修饰非成员函数
    • 5.1 修饰参数
    • 5.2 修饰返回值
  • 6.const修饰类对象
  • 7.const修饰类成员变量
  • 8.const修饰类成员函数
  • 9.mutable关键字
  • volatile关键字
  • 结合 const volatile 进一步理解const的存储

1.const修饰符的作用

const是一个语义约束,编译器会强制实施这个约束。它会指明变量或对象的值不能被改变
被const修饰,可以防止意外修改,增强程序的健壮性

2.const常量的存储

  • C++中,被const修饰的变量已经不在是一个变量了,而是一个常量。
    验证:
    【C++】const关键字详解 && volatile关键字了解_第1张图片

  • 在编译的时候全部替换为const修饰的变量的初始化值,在运行的时候该const变量可通过内存进行修改
    2.1通过内存(指针)可以修改位于栈区的const变量,语法合乎规定,编译运行不会报错,但是在编译的时候所有用到该常量的地方全部被替换成了初始化时所赋予的值,然后再运行的时候无法使用通过指针修改后的值
    【C++】const关键字详解 && volatile关键字了解_第2张图片
    从汇编角度再次验证我们上图的描述
    【C++】const关键字详解 && volatile关键字了解_第3张图片
    2.2通过内存(指针)修改位于静态存储区的的const变量,语法上没有报错,编译不会出错,一旦运行就会报告异常。
    【C++】const关键字详解 && volatile关键字了解_第4张图片

3.const修饰变量

表示该变量的值是只读的,不能被修改
由于const修饰的变量值不可被修改,所以const变量必须被初始化
【C++】const关键字详解 && volatile关键字了解_第5张图片

4.const修饰指针 && 引用

4.1修饰指针

重点关注 const在 * 的前面还是后面
【C++】const关键字详解 && volatile关键字了解_第6张图片

4.2修饰引用

const 修饰的引用称为 “常量引用”,常量引用不能直接修改所引用的对象
【C++】const关键字详解 && volatile关键字了解_第7张图片
一般来说,引用的类型要与其所引用的对象的类型一致
但也有特殊情况:
比如:
const修饰的引用引用相同类型的非const变量
【C++】const关键字详解 && volatile关键字了解_第8张图片
const修饰的引用类型与所引用对象类型不一致
此时,const修饰的引用并不是引用d(拿下图举例),而是对中间临时变量的引用
【C++】const关键字详解 && volatile关键字了解_第9张图片

4.3指针与引用的联系

  • 在底层实现原理上,引用是通过指针方式实现的
  • T&可以看做是 T* const类型的指针
    这也就解释了为什么一旦引用一个实体后,就不能在去引用其他实体。本质原因就是底层的const不允许它指向发生改变,也就导致了引用不能改变。
  • const T& 可以看做是 const T* const类型的指针

关于指针与引用的区别联系,感兴趣的朋友移步至指针&&引用

5.const修饰非成员函数

5.1 修饰参数

  • 函数参数列表中被const修饰的参数,在函数体内部不能被修改
    【C++】const关键字详解 && volatile关键字了解_第10张图片

  • const修饰函数参数对函数重载的影响
    1.参数为普通变量
    【C++】const关键字详解 && volatile关键字了解_第11张图片
    2.参数为指针变量
    要看const修饰的是哪一部分:
    2.1const修饰指针的指向【C++】const关键字详解 && volatile关键字了解_第12张图片
    2.2 const修饰指针指向的内容
    【C++】const关键字详解 && volatile关键字了解_第13张图片
    3.参数为引用类型
    构成重载~因为第一个引用的是变量,而第二个是对常量的引用
    【C++】const关键字详解 && volatile关键字了解_第14张图片

总结:
1、对于函数值传递的情况,因为参数传递是通过复制实参创建一个临时变量传递进函数的(形参实例化,创建临时对象),函数内只能改变临时变量,但无法改变实参,则这个时候无论加不加const对实参不会产生任何影响。
2、在引用或指针传递函数调用中,因为传进去的是一个引用或指针,这样函数内部可以改变引用改变指针所指向的变量,这时const 才是实实在在地保护了实参所指向的变量
3、在编译阶段编译器对调用函数的选择是根据实参进行的,所以,只有引用传递和指针传递可以用是否加const来重载

5.2 修饰返回值

  • 值传递方式
    函数会将返回值复制到外部临时的存储单元中,加const修饰没有任何价值,因为临时的存储单元本来就具有常性。只能使用他的右值
  • 指针传递方式
    1、int* const fun()
    【C++】const关键字详解 && volatile关键字了解_第15张图片
    2、const int * fun()int const *fun()
    它两效果等价
    【C++】const关键字详解 && volatile关键字了解_第16张图片
  • 修饰引用返回值
    使用要点:返回的引用不能是函数内临时变量的引用。

6.const修饰类对象

const修饰类对象时与const修饰变量并无实质不同,只是在于类对象的“改变”定义。
被const修饰的类对象,既不能改变类中的成员变量,也不能调用类中任何非const成员函数
【C++】const关键字详解 && volatile关键字了解_第17张图片

7.const修饰类成员变量

const修饰的成员变量不能被修改,所以只能在初始化列表中被初始化,和类中的引用成员变量一样
【C++】const关键字详解 && volatile关键字了解_第18张图片

如果是const修饰的静态成员变量,因为属于整个类,而不是对象,不可以在初始化列表的位置进行初始化。(其实这是static存在的原因,这里是想要强调另外一点,见下图)
【C++】const关键字详解 && volatile关键字了解_第19张图片

8.const修饰类成员函数

本质:修饰的是该成员函数隐含的this指针
【C++】const关键字详解 && volatile关键字了解_第20张图片
const修饰成员函数表示此函数不能对任何成员变量进行修改
一般const写在函数的后面,形如:int func() const;
【C++】const关键字详解 && volatile关键字了解_第21张图片
下面是4道经典的问题,感兴趣的朋友们移步至 const几个经典问题
【C++】const关键字详解 && volatile关键字了解_第22张图片

9.mutable关键字

存在的意义:为了突破const的限制而设置的,可以用来修饰一个类的成员变量。被 mutable 修饰的变量,将永远处于可变的状态,即使是 const 函数中也可以改变这个变量的值
【C++】const关键字详解 && volatile关键字了解_第23张图片
对于const修饰的类对象,也是可以修改mutable修饰的成员变量
【C++】const关键字详解 && volatile关键字了解_第24张图片

volatile关键字

浅谈我个人对volatile关键字的一些认识:
它被称为 最易变的关键字
作用:保持内存可见性
画图理解:(仅是个人理解,有不对的地方还请海涵)
【C++】const关键字详解 && volatile关键字了解_第25张图片
对于这种情况,称为系统的优化。
【C++】const关键字详解 && volatile关键字了解_第26张图片
下面我就通过Linux平台下验证一下:
【C++】const关键字详解 && volatile关键字了解_第27张图片
编译代码,使用优化命令 -O2
【C++】const关键字详解 && volatile关键字了解_第28张图片
将代码反汇编,查看汇编代码
【C++】const关键字详解 && volatile关键字了解_第29张图片
打开a.s,查看汇编代码
【C++】const关键字详解 && volatile关键字了解_第30张图片
仔细观察上图,我们发现,其实CPU在将value值第一次读进寄存器后,代码执行到最后直接是自己调用自己,连从寄存器取值也不会执行!!

看到这里,验证也就进行了一半了
接下来,我们将value变量用volatile修饰
【C++】const关键字详解 && volatile关键字了解_第31张图片
OK!那么为什么要有volatile关键字呢?
(以上例说明)
原因是在某些情况下,我们需要时刻读取内存中变量(value)的值在确定程序下一步该如何执行,尽管在我们现在的认知里,只要这个进程不改变内存中变量(value)的值,那么他就会一直运行下去。
那是因为我们没有了解过多线程等相关知识。如果在这种情况下,其他的线程可能会修改内存中value的值,进而导致该循环可能会无法执行。
如果我们用volatile关键字修饰该变量,那么它每次都会从内存读取该数据,也就不会有上面的情况了。

请问:const volatile int a = 10;这条语句可以编译通过吗?
答案是可以的。
那有人就有疑问了,const要求不进行写入,volatile是最易变的关键字,二者之间不冲突吗?
这里volatile的叫法有些迷惑性。volatile的真实含义是在读取数据的时候,每次都要从内存读取。
这里的易变指的是它修饰的变量可能会变化,要编译器注意。并不是说它要求对应变量必须变化。

注意:
const是在编译期间起效果
volatile在编译期间主要影响编译器,形成不优化的代码,进而影响运行。故编译和运行都起效果

结合 const volatile 进一步理解const的存储

const volatile修饰的变量,可以在编译时不用全部替换被const volatile变量被赋予的值,因此可以在运行时使用通过内存修改后的值

1、通过内存(指针)可以修改位于栈区的const volatile变量,语法合乎规定,编译运行不会报错,在编译的时候所有用到该常量的地方不会替换成了定义时初始化的值,在运行的时候可以使用通过指针修改后的值。
【C++】const关键字详解 && volatile关键字了解_第32张图片
2、通过内存(指针)修改位于静态存储区的的const volatile变量,语法上没有报错,编译不会出错,一旦运行就会报告异常。
【C++】const关键字详解 && volatile关键字了解_第33张图片

写到这里,就我目前学到的知识来看,我眼中的const就是这样~
当然,后续学习过程中,如果遇到其他的特性,我会回来更新的。
既然都看到这里了,那就三连一波儿,留下你的足迹吧!!!
【C++】const关键字详解 && volatile关键字了解_第34张图片

你可能感兴趣的:(C++,c++,后端)