C++ const详解

一.const出现的意义

被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性.这是我们最常看到的一句话。但是我们常常将const和其他技术相结合使得程序更加优秀。

二.const修饰符的使用场景

1.修饰变量
1.1 其中修饰变量也有很多种情况,我们先来分析内存的不同情况
代码:

#include<iostream>
using namespace std;
int i=0;
static int j = 0;
int k;
const int a=1;
const static int b = 2;
int main()
{
	const int c=1;
	const static int d=2;
	static const int e=3;
	
	printf("%p\n",&i);
	printf("%p\n",&j);
	printf("%p\n",&k);
	printf("%p\n",&a);
	printf("%p\n",&b);
	printf("%p\n",&c);
	printf("%p\n",&d);
	printf("%p\n",&e);
} 

运行结果:

在这里插入图片描述
分析:
我们根据内存模型详解https://editor.csdn.net/md/?articleId=121130997分析i,j,k都是分配在全局静态区。我们观察到a,b的地址与i,j,k
有很大的不同。a,b应该在内存的常量区。这就说明在函数外定义变量只要加上const除了可以让变量变得不可修改还可以改变变量内存分配的实际位置。我们观察c,d,e,我们发现从d,e与a,b的地址相近,所有d,e是在常量区,那么c就只可能在栈区了。所有在函数内给变量const可以让变量变得不可修改,如果要改变变量分配区域需要加上static(const static顺序无关)
小结:
const基础作用,防止修改值(可以取代宏定义,变得类型安全)
在函数外加上const 内存分配区从全局区变成常量区
在函数内加上const 内存依然在栈区,除非同时加上static(顺序无关)

我们使用const_cast去掉const,继续测试

#include<iostream>
using namespace std;
int main()
{
	const static int d=2;
	const int i = const_cast<int&>(d);
	int j = const_cast<int&>(d);
	static int k = const_cast<int&>(d);
	printf("%p\n",&d);
	printf("%p\n",&i);
	printf("%p\n",&j);
	printf("%p\n",&k);
} 

运行结果:
在这里插入图片描述
我们知道:
d分配在常量区,
我们用const_cast去掉static后内存分配在栈区,
用 const_cast去掉const和static也分配在栈区
我们用const_cast只去掉const内存分配在静态区
综合上述测试结果,我们得出结论:
函数外:
没有const,没有 static,分配在全局区;
没有const,有 static,分配在全局区;
有const,没有 static,分配在常量区;
有const,有 static,分配在常量区;
函数内:
没有const,没有 static,分配在栈区;
没有const,有 static,分配在全局区;
有const,没有 static,分配在栈区;
有const,有 static,分配在常量区;

1.2 const修饰一般参数作为形参
代码:

#include<iostream>
using namespace std;
void func(int a,int b,const int c)
{
	printf("%p\n",&a);
	printf("%p\n",&b);	
	printf("%p\n",&c);
} 
const int a=1;
int main()
{
	const int b=1;
	printf("%p\n",&a);
	func(a,a,a);
	printf("\n");
	printf("%p\n",&b);
	func(b,b,b);
} 

运行结果:
在这里插入图片描述
分析:根据上文,a,b分配在常量区和栈区.我们调用函数,很明显,形参全是分配在栈上。

2.const修饰引用
测试代码:

#include<iostream>
using namespace std;
int i=1;
const static int & j = i;
const int & k = i;
int main()
{
	int a=1;
	const static int & b = a;
	const int & c = a;
	printf("%p\n",&a);
	printf("%p\n",&b);
	printf("%p\n",&c);
	
	printf("%p\n",&i);
	printf("%p\n",&j);
	printf("%p\n",&k);
} 

运行结果:
在这里插入图片描述
分析 我们发现const 修饰引用的时候,在函数内外都不能改变实际分配的地址,只能保护该地址的值不能修改。这样就有一个好处,我们可以把函数形参改成常引用的形式,这样我们既有引用的效率优势(别名)又有const的安全性(不可修改)

3.const修饰指针
const 修饰指针分为四种情况(实际上就是三种):

const 变量类型 * 变量名;
变量类型 const  * 变量名;
 变量类型 * const 变量名;
const 变量类型 * const 变量名;
#include<iostream>
using namespace std;
int main()
{
	int a=1;
	const int * p1 = &a;
	int const * p2 = &a;
	int * const p3 = &a;
	const int * const  p4 = &a;
	
	//*p1=1;,错误,不能修改指针指向的值 
	p1++;
	
	//*p2=1;错误,不能修改指针指向的值 
	p2++;
	
	*p3=1;
	//p3++; 
	
	//*p4=1;错误,不能修改指针指向的值 
	//p4++;错误,不能修改指针指向的地址
} 

分析;
当我们将const 放在星号之前,我们不能修改指针指向的值
当我们将const 放在星号之后,我们不能修改指针指向的地址
当我们将const 放在星号之前和之后,我们不能修改指针指向的值和地址

方便记忆:
有两种大致情况
const 星号 变量名 = const (星号 变量名) = const (值) = 不能修改指针指向的值
星号 const 变量名 = 星号 const ( 变量名) = 星号 const (地址)= 不能修改指针指向的地址

4.修饰函数返回值

这个没什么好说的,返回值是不能修改的,如果返回的是常量指针对应上面第三种情况

5.修饰成员函数
被const修饰的成员函数叫做常成员函数;
先说一下类中哪些函数不能被const修饰吧:
构造函数不能
析构函数不能
拷贝构造函数不能

可以设置为const 的函数:
普通成员函数
虚函数
纯虚函数
重载操作符函数

来说一下const修饰函数的作用吧
防止成员变量被修改,,原理是将this指针改成const,表明在该成员函数中不能对类的任何成员进行修改。
使用方法:

class A
{
	int a=1;
	public:
	void foo(int& b) const
	{
		b=1;
	}
}; 
class B:A
{
	int a=1;
	void func()
	{
		foo(a);//可以指向 
	}
};

分析:我们发现const,只能包含本类的成员不被修改,不能保证子类不修改子类成员(const保护的是本类的this指针!)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值