C++中的const限定符

1 简介

const,顾名思义代表一个常数。在定义变量时若是以const加以限定,则说明该变量已经被转换为了常量,其字面值无法被改变,否则会报错。定义一个常量的语法如下所示:

const int bufSize = 512;

通过上述语句,我们定义了一个int类型的常量bufSize,其字面值为512,且不能改变。

2 初始化

由于const对象一旦创建后其值就不能被改变,因此在定义const对象的时候必须同时进行初始化。例如,若是将上面的代码改为const int bufSize;,则编译器会报错,因为并没有对其进行初始化工作。除了直接使用数值来进行初始化之外,我们也可以利用其他的对象来对const对象进行初始化,该对象是不是const都无关紧要。此外,const对象也可以用来初始化其他的对象,例如:

int i = 42;
const int ci = i;
int j = ci;

我们可以看到,i是一个整型变量,可以被用来初始化整型常量ci,与此同时整型常量ci又被用来初始化整型变量j。一般来说,在使用const对象时就把它当成一个常数就可以。

3 const与指针和引用的结合

3.1 指针

由于指针本身就是一个对象,它又可以指向另外一个对象,因此指针本身是不是常量以及指针所指的是不是一个常量就是两个相互独立的问题。一般来说,用名词顶层const(top-level const)表示指针本身是个常量,用名词底层const(low-level const)表示指针所指的对象是一个常量。观察下面的例子:

const int i = 1;
int *const p1 = &i;
const int* p2 = &i;
const int *const p3 = &i;

在上面的例子中,我们首先定义了一个常量i,其值为1。p1、p2、p3分别为三个指针,我们来依次对它们进行分析:

  • p1是一个常量指针,代表它的值永远不会改变,p1的const是顶层const;
  • p2指向的是一个整型常量,也即p2指向的对象必须是由const int来定义的,p2的const是一个底层const;
  • p3的情况要复杂一点。首先,紧挨着p3的const代表p3的值不能改变,是一个顶层const,之后int前面的const告诉我们p3还应该指向一个整型常量,是一个底层const。

可能有的读者会觉得进行这种判断比较复杂,其实不然。只需要记住两点:const只修饰它后面紧挨着的内容,判断这种复合类型的时候从里往外看。依旧用const int *const p3 = &i;来举例子,首先从里往外看,最里面的const后面紧挨着p3,因此代表p3指针是一个常量,它的值不能改变。之后再往外找,外层的const后面紧挨着int,这说明该指针指向的数据类型应该是一个整型的常量,从而就完成了对p3类型的判断。其实其他的一些复杂的复合类型的判断方法也是如此,比如指针和数组的结合等。

3.2 引用

引用,就好比对一个是为一个已经存在的对象所起的另外一个名字,二者都被绑定在了同一个值上。举例来说:

int i = 0;
int &r = i;

这里的i是一个整型变量,r是一个引用,i和r都被绑定在了字面值0上,修改i或者r的值都会影响这个字面值。如果将引用绑定在const对象上,我们就称之为对常量的引用。但与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象。例如:

(1) const int i = 1;
(2) const int &i1 = i;
(3) i1 = 2;
(4) int &i2 = i;

在第一行中我们定义了一个整型常量i,其值为1,第二行中定义了一个常量引用i1。第三行是错误的,因为不可以通过常量引用去修改常量的值。这一点其实很容易理解,因为常量引用和常量本质上来说都被绑定在了同一个对象上,而常量的值一旦定义就无法被改变了。第四行也是错误的,因为i2的类型是一个普通的整型的引用,而不是一个常量引用,若是在开头加入const则是正确的。

4 constexpr常量表达式

常量表达式,是指不会改变并且在编译过程中就能得到计算结果的表达式。表达式,是由数字、算符、数字分组符号(括号)、自由变量和约束变量等以能求得数值的有意义排列方法所得的组合。一个对象是不是常量表达式是由它的数据类型和初始值共同决定的,例如,假设 max_files是一个值为20的整型常量,则max_files + 1就是一个常量表达式。但是在一个复杂的系统中,几乎不能分辨一个初始值到底是不是常量表达式。因此C++ 11的标准中允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个而常量表达式。声明为constexpr的变量一定是一个常量,而且必须用常量表达式来初始化。

5 其他需要注意的地方

在编译时以初始化的方式定义一个const对象时,编译器将在编译的过程中把用到该变量的地方都替换成对应的值。为了避免对同一变量的重复定义,默认情况下const对象被设定为仅在文件内有效。如果多个文件中出现了同名的const变量时,则等于在不同的文件中分别定义了独立的变量。举例来说,现在有两个文件file1file2,若是它们中都定义了const对象bufSize,则这两个bufSize会被看作是两个独立的变量,没有任何的联系。
有的时候我们必须要让const对象在文件之间共享,这时候不管是定义还是声明都需要用extern关键字加以修饰,这样只需要定义一次就可以了。例子如下:

// file1.cpp 定义并初始化了一个常量
extern const int bufSize = 512;
// file1.h 头文件
extern const int bufSize;

你可能感兴趣的:(C++中的const限定符)