C++中 const解析

一、const基础

const修饰的是常量,定义的时候必须初始化,(假如不初始化也就不能再赋值了,也就没用了😹。这里只做举例说明。const常量不能直接对const常量进行修改,但可以通过其他手段进行修改(伏笔,并且只能修改局部const常量)。
const常量问题必须得区分全局与局部,因为在全局中定义与在局部定义是不一样的。全局:const常量是存储在符号表里面的,默认是没有地址的,当获取了地址之后,就会分配在全局常量区。所以全局const常量是不能修改的;而对于局部const常量,是一开始就会分配地址的,可以通过地址去修改const常量所对应的地址的值。但还是不能修改const常量的值,这点会在后面进行详细说明。

#1.1 代码说明全局const常量与局部const常量的区别

1.1.1 全局const常量

#include<iostream>
using namespace std;

int test = 10;

int main()
{
	int a = 10;
	system("pause");
	return 0;
}
&test	0x00d90000 {10}
#include<iostream>
using namespace std;

const int test = 10;

int main()
{
	int a = 10;
	system("pause");
	return 0;
}

在这里插入图片描述

1.1.2局部const常量

#include<iostream>
using namespace std;

int main()
{
	const int test = 10;
	int a = 10;
	system("pause");
	return 0;
}
&test	0x0037fcf0 {10}	

1.2 格式说明*

const int a;
int const b;
//以上这两种写法是一样的

const int *c;  //const修饰的是指针所指向的内存空间,不能被修改
int *const d;  //const修饰的是指针变量,即指针变量本身不能被修改
const int *const e;  //指针变量以及其所指向的空间都不能被修改

const作用于指针的时候:哪个靠的近就作用于哪个。const int *c 对指针指向的对象,而int *const d 则是不能对指针的值进行修改。

#include <iostream>
typedef struct Teacher{
    char name[64];
    int age;
}Teacher;

//指针所指向的内存空间,不能被修改
int operatorTeacher01(const Teacher *pT){
    //pT->age = 10;//编译错误
    return 0;
}

//指针变量本身不能被修改
int operatorTeacher02(Teacher * const pT){
    pT->age = 10; //所指向的内存空间可以被修改
    //pT = NULL; //编译错误 pT本身不能被修改
    return 0;
}

//指针变量所指向的内存空间和指针变量本身都不可以被修改
int operatorTeacher03(const Teacher * const pT){
    //pT->age = 10;//编译错误
    //pT = NULL;//编译错误
    std::cout << "age:" << pT->age;
    return 0;
}

int main(){
    //尝试调用operatorTeacher03方法
    Teacher t1;
    t1.age = 33;
    operatorTeacher03(&t1);
    return 0;
}

总结:
1、指针做函数参数,可以有效的提高代码的可读性,减少bug
2、清楚的分清楚参数的输入和输出特性

二、const 实现机理探究

const 变量在编译的时候,会根据定义的是全局变量还是局部变量,以及后续的情况,来决定是否给const常量分配内存空间。并且还会在符号表中有一个const常量所对应的值。

对全局变量而言,它是默认不分配地址的,除了extern声明与一些需要取地址的操作。并且在分配了地址之后,也是存储在常量区的,所以对于全局const常量而言,它是不允许被修改的。

而对于局部const常量是默认分配地址(在我的实验里是这样的,但还是很多博客说不分配的,只在取地址的时候才会分配),但是默认是不能够对const地址进行赋值的,所以也不能够直接通过地址去访问修改const常量,但有一个强制转化可以突破这个限制,const_coat<> 这个可以让将const常量地址赋值给一个指针。但是这里也不能够修改const常量,因为这里会用到一个叫常量折叠的概念。它的大概流程就是,有一个int 类型的const常量a,一个指针b,b指向a的地址,但分别通过a与b访问这块地址值的时候,结果却不一样。具体实现是这样的,就是 a 是const常量,但编译器看到a时,它不会访问a这块地址的值,而是在符号表里面去访问a所对应的值,但b还是直接访问的是a地址所代表的值,所以后面两者的值不一样。这个是编译器的预处理操作,同样在引用里面也是如此。其实引用就是一个指针,但你在访问引用的地址的时候,访问的却不是引用自身的地址,而是引用的内容。但正是引文这样,引用才会用起来更加顺手。正如C++创始人Bjarne Stroustrup 所说,他在 C++ 中引入引用的直接目的是为了让代码的书写更加漂亮,尤其是在运算符重载中,不借助引用有时候会使得运算符的使用很麻烦。
在这里插入图片描述
符号表:符号表是一种用于语言翻译器(例如编译器和解释器)中的数据结构。

三 const在c与c++中的比较

1、C语言中的const是一个冒牌货,C++中 const才是一个真正的常量

2、原因分析

C语言中,定义的const会分配一个内存空间
并且可以const常量地址进行赋值操作。由于C语言没有对指针访问进行限制。(访问指针可以帮助我们突破一些访问极限,比如访问private变量。
 
C++中,编译器对const做了特殊处理,不允将const常量的地址进行赋值操作。所以不能直接通过指针去改变const常量。但可以通过强制类型转换,对const常量的进行赋值操作,但由于常量折叠的存在,const常量还是保持了不变。千变万变,我const绝对不变。

但有一个问题没有搞懂,就是在访问局部const常量的时候,它是访问的符号表中的值,还是对应的那款地址存储的值。

但对const变量进行访问的时候,则会对符号表进行访问,读取const变量所对应的值。其实只是简单的通过的变量去访问变量,跟c语言没有太大区别;跟c语言的区别就在于,它对于指针访问的限制

#include <stdio.h>
int main(){
    //看起来好像a是一个常量,其实不然
    const int a = 10;
    //a = 11;
    int *p = NULL;
    p = (int *)&a;

    *p = 20; //间接赋值
    printf("a:%d\n",a);//在C语言中,a变成了20,而在C++中,a依然是10
    return 0;
}

上面这段代码,放在c与c++中去执行,就会得到不一样的效果,尽管这个同一段代码。就反应出了C与C++对于const的不同处理。
我这里来解释一下:
C中:

p = (int *)&a;

直接将a的地址赋值给p,然后通过p去访问const a。这个操作很符合c语言的习惯,所以后面的结果就是可以通过p来访问修改const变量。

而在C++中

p = (int *)&a;

这里p也是得到的a的地址,但有一个点请注意,这个a的地址并不是我们在访问const变量a时的地址,我们访问的a是存储在符号表的。那么这个的&a是谁的地址,这里其实也是a的地址,更加准确的来说是a的拷贝值的地址。

	const int i = 1;
	int* k = (int*)(&i);
	*k= *k + 3;
	printf("const i 的地址为:%p ,其值为%d\n\n", &i, i);
	printf("k 的地址为:%p ,其值为%d", k, *k);

在这里插入图片描述

可以看到,i跟k 的地址是一样的,但最后输出的时候,i的值却不等于k的值,原因就是当访问i的时候,访问的是符号表里面的值。

结论:

  1. C语言中的const变量是只读变量,有自己的存储空间

  2. C++中的const常量

  • 可能分配存储空间,也可能不分配存储空间

  • 当const常量为全局,需要取地址的时候才会跟const全局常量分配地址。

  • 当const常量为局部,默认就会分地址。

全部的结果都是基于VS2019

参考资料:
https://blog.csdn.net/qq_39776901/article/details/78090662
https://blog.csdn.net/hzh2007/article/details/12006855
https://blog.csdn.net/weibo1230123/article/details/82777510
https://blog.csdn.net/woainilixuhao/article/details/86521357
https://blog.csdn.net/xiazhiyiyun/article/details/71969618?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值