C++ Const


  使用 const 关键字修饰的变量的值不能修改,称为常量,但是 C 语言中实际上可以通过指针修改常量的值,C++ 中则不能。

注意:本文目前存在一定问题,校对中,请勿当作严格的参考!

由于指针的存在,指针变量有三种状态: const type *, type * const, const type * const,即 const 修饰基本数据类型,const 修饰指针,const 修饰指针和基本数据类型。

在 C++ 中,常量是严格禁止修改的,但是在 C 中,可以通过强制类型转换为一个普通指针类型的临时变量,通过这个变量修改原本的数据:


const int a = 0;
int *p = (int *)&a;
*p = 1;//合法且a变成1,这是 C 不安全的原因之一

const 修饰基本数据类型被称为底层(low-level) const,const 修饰指针被称为顶层(high-level) const,并且由于指针也可以指向指针,引用也可以是指针(默认被 const 修饰),所以在使用上又复杂许多。

指针和引用

话不多说上代码:


1 int ival = 1;
2 int &re = ival;   //re是对ival的引用
3 int &re2 = &ival;   //错误,引用的对象不能是地址
4 int *pi = &ival;   //pi是指向ival的指针
5 int *&pi2 = pi;   //ok,pi2是一个对指针的引用

根据汇编代码可以得到,引用在底层实现上和指针是一样的,区别只在于引用的对象一定不为空,并且引用默认被 const 修饰。 不过标准通过编译器额外对引用增加了一些限制,避免在二义性做出选择。

顶层 const 和底层 const


int i = 0;
const int * p1 = &i;
int *x = p1; // 错误,*x不具备底层const资格
const int *x2 = p1; // 正确,具备底层const资格
const int *x3 = &i;  // 正确,&i是int *,可以转成const int *


int num_a = 1;
int const  *p_a = &num_a; //底层const
*p_a = 2;  //错误


int num_b = 2;
int *const p_b = &num_b; //顶层const
p_b = &num_a;  //错误


#include <cstdio>
int main(){
	int num_c = 3;
	int num_d = 4;
    const int *const p_c = &num_c;
	*p_c=4;    //expression must be a modifiable lvalue
	p_c = & num_d;    //expression must be a modifiable lvalue
	num_c = 4;
	const int num_e = 5;
	num_e = 6;   //expression must be a modifiable lvalue
	getchar();
}

通过上面的代码可以看到,既可以直接用 const 修饰基本数据库类型,也可以在声明指针的时候,用底层 const 修饰指针,此时无法根据指针修改数据的值。

此时需要注意一点,const 修饰的变量是不可以赋给普通变量的。同理,如果函数的形参非 const,而实参是 const,那么这段程序就是错误的,此时需要 const_cast。

const_cast

用法:const_cast (expression)

const_cast 可以在调用时忽略 const 或者添加 const,并不能改变原有的 const 状态。

type 可以使用 type 本身,也可以使用被 const 修饰的 type(如const_cast <const type> (expression)),这种情况一般不需要,因为非 const 修饰的变量可以直接赋给 const 修饰的变量。

数组的指针和指针的数组


char *arr[4]; //这个数组每个元素都是一个指针
char (*pa)[4];//pa是一个指向数组的指针

再看如下代码:


char *arr[4] = {"hello", "world", "string1", "string2"};

arr 是一个指针数组,有四个元素,每个元素是一个char *类型的指针,这些指针存放着其对应字符串的首地址。

数组 arr[4] 的四个指针元素,分别存放着这四个字符串的首地址,arr+1 会跳过四个字节,也就是一个指针的大小,达到下一个元素的首地址。 这就相当与定义char *p1 = “hello”,char *p1 = “world”,char *p3 = “string1”, char *p4 = “string2”,这是四个指针,每个指针存放一个字符串首地址,然后用arr[4]这个数组分别存放这四个指针,就形成了指针数组。

参考:https://www.dyxmq.cn/program/code/c-cpp/cpp-const-4-top-level-const-and-low-level-const.html https://www.zhihu.com/question/37608201 https://blog.csdn.net/men_wen/article/details/52694069