const基础与一级指针,二级指针,引用的结合

const基础与一级指针,二级指针,引用的结合

 

const基础:

在之前学习C语言的时候,我们就写过const,现在学习了C++,发现之前对于const的理解有些偏差,不够深刻。今天,我们就深入探索一下在C语言和C++下const的区别。

 

一:const在C和C++中的区别

①:在C语言中,被const修饰的内容称作常变量。它本质是一个变量,因此,C语言中const修饰的变量并不能作为初始化数组长度的下标。

其特点只有一个:被修饰的内容不可以作为左值存在。

②:而在C++中,const修饰的内容叫做常量,在编译阶段会被当作立即数,可以当做初始化数组长度的下标。

其特点有两个:1.必须初始化,初始化的值必须是常量。 2.不允许普通的指针指向,只能用const类型的指针指向。

 

两者区别:

C语言里用const修饰的值可以不初始化,只是之后再没有机会对这个const修饰的变量赋值了。因此我们可以得出c语言里const定义的常变量和一般变量的区别很小,只是常变量定义后不能作为左值存在。但其本质,或者说是编译方式,和普通变量是一样的。

 

而在C++中,const修饰的量必须初始化,否则编译无法通过,即在编译的时候编译器会把使用const修饰的量都替换为其本身的值,因此就能作为数组下标了,因为编译时,编译器看到的下标并非const 定义的变量的名字,而是它对应的值的立即数。

 

我们下面将验证一下我们的结论:

①:

我们在.cpp文件中写下了这些代码,最终打印的结果是10和20,我们可以得出结果,程序运行后,指针p指向了a的内存,修改了a的值,这时a内存里存放的值就为20了,为什么最后打印a的值为10,不是20呢?

因为编译阶段已经把要打印的a换成了10这个立即数了,不会因为程序运行后,a值的改变而改变。

 

②:

刚说过c++里的const修饰的量必须初始化。初始化的值必须是个常量,不能是个普通变量,这样的原因是编译器编译时,替换const常量将会不明确,只有立即数或者之前定义过的const常量是明确的具体的数字。

我们这里看到b不能作为初始化数组长度的下标了,因为将变量a赋值给了常量b,b会退化成成为常变量。

而这里,我们间定义好的const常量赋值给了b,是允许的。

 

PS:并且在C++中,这个const修饰的数据,最终生成的符号是local属性的,即只有本文件可见的。因为编辑器不关注local区域,只关系global区域。

如果想要把const修饰的数据供整个工程使用,生成global全局符号,那么其实也有一种方法,就是在定义处前面加extern声明。让其属性由local ---> global。

即:

const int a = 10;         //本文件可见

extern const int a = 10;   //本工程可见

 

 

const与一级指针的结合:

有一种说法:在C++中,const只是为了防止间接访问的风险。

下面我们来看看不同的情况下const与一级指针的结合结果:

 

 

 

 

const与二级指针的结合:

有一种说法:在C++中,const只是为了防止间接访问的风险。

下面我们来看看不同的情况下const与二级指针的结合结果:

 

 

 

 

现在我们看看最特殊的一种,我们放到这里来讨论:

根据我们一般的判断,const修饰的是 **q,直接访问为a,从const修饰的那一行开始看,间接访问只有**q,而**q还被const修饰了,应该是没有问题的。

但是运行结果:

从C语言来看,它的权限是缩小的,为什么不行呢,我们来看下面这几行代码:

 

我们来画图分析:

所以我们有两种方法可以防止第三行代码存在的风险:

①:我们通过给*q前加const,则意思为我不允许通过*q的方式去让指针p随意指向

②:我们通过给*p前加const,则意思为我允许你通过*q的方式去让指针p随意指向,但是就算你随意指向了一个危险区域,我禁止了你通过*p的方式去修改它。

总结:

第一种:你别随便指向了,现在指向的就很安全。因为现在指向的空间要莫为NULL,要么是允许修改的。

第二种:你可以随便指向,但是你别想修改这快内存空间的值,权限为只读,不可写。

 

 

现在,回到开头,处理我们的特殊问题:

这里,我们就可以类比上面直到,第三行代码,存在通过*q去修改指针p的指向,让其指向一个危险区域,修改里面的值。

 

所以根据我们的得出的两种处理方法处理这段代码:

①:不允许你通过*q去修改指针p的指向

②:可以通过*q去修改指针p的指向,但是不允许通过*p去修改里面的值

 

 

 

const与引用的结合:

开始我们讲过,引用不能引用常量

那这里我们前面加上const,为什么可以呢?

我们进入反汇编看一看:

这里我们可以看到,它先开辟了空间,存储常量20,再将这个空间的地址放入寄存器eax中,最终将eax中的值放到空间C中。所以引用变量c引用的是临时变量,称作常引用。

结论:常引用可以引用立即数:①:立即数放到临时量中 ②:常引用来引用临时量

 

 

 

我们之前说过,引用不参与类型,我们可以通过 左操作数的权限 <= 右操作数的权限 来判断const与引用是否结合成功

下面我们来看看不同的情况下const与引用的结合结果:

const与引用与普通变量的结合:

 

 

 

const与引用与指针变量的结合:

 

 

 

 

现在我们看看最特殊的一种,我们放到这里来讨论:

根据我们一般的判断,从const修饰的那一行开始看,第三行:左操作数权限const int* 是小于 右操作数权限int* 的,从权限判断来看,应该是没有问题的。

但是运行结果:

这里为什么不通过呢,原因很简单,和上边那个特殊的情况一样,第三行存在修改常量内存块的风险。即通过引用变量q赋值可以修改指针p的指向,让其指向一个危险区域,修改里面的值。

 

处理方法也和上面一样:

①:不允许你通过引用变量q赋值去修改指针p的指向

②:可以通过引用变量q赋值去修改指针p的指向,但是不允许通过*p去修改里面的值

 

 

 

const 和引用符号&:

我们先来看一下,&要不要紧跟着引用变量名,也就是可不可以出现 int &const b这种情况

事实证明,编译器会发出警告,证明&要紧跟着引用变量名。

 

 

形参加上const的作用(针对下面):

  1. 防止实参被修改
  2. 允许使用立即数

 

引用做形参和普通变量做形参的区别:

  1. 引用做形参可以修改实参的值
  2. 引用做形参不能引用立即数,部分实参可能无法调用(引用本质是指针,做形参是要传地址进去的,而立即数是无法取地址的,所以不行)

 

猜你喜欢

转载自blog.csdn.net/IT_Quanwudi/article/details/84573239