C++ 第七章 指针、数组与引用 - 7.5 指针与const

第七章 指针、数组与引用

7.5 指针与const

C++提供了两种与“常量”有关的概念:

  • constexpr:编译时求值(见2.2.3节和10.4节)。
  • const:在当前作用域内,值不发生改变(见2.2.3节)。

基本上,constexpr的作用是指示或确保在编译时求值,而const的主要任务是规定接口的不可修改性。本节主要关注第二点:接口说明。

很多对象的值一旦初始化就不会再改动:

  • 使用符号化常量的代码比直接使用字面值常量的代码更易维护。
  • 我们经常通过指针读取数据,但是很少通过指针写入数据。
  • 绝大多数函数的参数只负责读取数据,很少写入数据。

为了表达一经初始化就不可修改的特性,我们可以在对象的定义中加上const关键字。例如:

const int model = 90;		//model是一个const
const int v[] = {
    
    1,2,3,4};	//v[i]是一个const
const int x;				//错误:缺少初始化器

因为我们无法给const对象赋值,所以它必须初始化。

一旦我们把某物声明成const,就确保它的值在其作用域内不会发生改变:

void f()
{
    
    
	model = 200;		//错误
	v[2] = 3;			//错误
}

使用const会改变一种类型。所谓改变不是说改变了常量的分配方式,而是限制了它的使用方式。例如:

void g(const X* p)
{
    
    
	//此处无权修改*p
}
void h()
{
    
    
	X val;		//此处可以修改val的值
	g(&val);
	//...
}

一个指针牵扯到两个对象:指针本身以及指针所指的对象。在指针的声明语句中“前置”const关键字将令所指的对象而非指针本身成为常量。要想令指针本身成为常量,应该用const代替普通的。例如:

void f1(char* p)
{
    
    
	char s[] = “Gorm”;

	const char* pc = s;			//指向常量的指针
	pc[3] = ‘g’;				//错误:pc指向常量
	pc = p;						//OK

	char *const cp = s;			//常量指针
	cp[3] = ‘a’;				//OK
	cp = p;						//错误:cp是一个常量

	const char *const cpc = s;	//指向常量的常量指针
	cpc[3] = ‘a’;				//错误:cpc指向常量
	cpc = p;					//错误:cpc本身是一个常量
}

声明运算符const的作用是令指针本身成为常量。不存在形如const的声明运算符,相反,出现在*前面的const是基本类型的一部分。例如:

char *const cp;		//指向char的常量指针
char const* pc;		//指向常量const的指针
const char* pc2;	//指向常量char的指针

要想理解上述声明的含义,一个小技巧是按照从右向左的顺序读。例如,“cp是指向char的const指针”,而“pc2是指向char const的指针”。

对于同一个对象来说,通过一个指针访问它时是常量并不妨碍在其他情况下它是个变量。这一点在涉及函数的实参时特别有用。我们可以把指针类型的实参声明成const,这样就能阻止函数修改该指针所指的对象了。例如:

const char* strchr(const char* p, char c);	//找到在字符串p中字符c第一次出现的位置
char* strchr(char* p, char c);				//找到在字符串p中字符c第一次出现的位置

第一个函数的参数是常量字符串,函数无权修改其中的元素;它的返回值是指向const的指针,也不允许修改其所指的对象,第二个函数没有这些限制。

C++允许把非const变量的地址赋给指向常量的指针,这不会造成什么不可接受的后果。相反,常量的地址不能被赋给某个不受限的指针,因为如果这样的话,用户有可能通过该指针修改对象的值,这显然是不被允许的。例如:

void f4()
{
    
    
	int a = 1;
	const int c = 2;
	const int* p1 = &c;		//OK
	const int* p2 = &a;		//OK
	int* p3 = &c;			//错误:用const int*初始化int*
	*p3 = 7;				//试图改变c的值
}

C++允许通过显式类型转换的方式(见16.2.9节和11.5节)显式地移除掉对于指针指向常量的限制,但是一般情况下不要这么做。

猜你喜欢

转载自blog.csdn.net/qq_40660998/article/details/121852607