当 pointer 和 reference 遇上 const

作者 Shilei Tian 日期 2016-09-12
C++
当 pointer 和 reference 遇上 const

这里旨在通过 C++ Primer 5e 中的 Section 2.4.2 部分的习题对 const 和指针、引用结合时候的各种情况进行解析,希望能够彻底理解这里面的玄关。

Exercise 2.27: Which of the following initializations are legal? Explain why.

1
2
3
4
5
6
7
(1) int i = -1, &r - 0;
(2) int *const p2 = &i2;
(3) const int i = -1, &r = 0;
(4) const int *const p3 = &i2;
(5) const int *p1 = &i2;
(6) const int &const r2;
(7) const int i2 = i, &r = i;

(1) 非法。这个声明等效于 int i = -1; int &r = 0;,但 0 是常量,不能声明一个对常量的非常量引用,否则我们就可以通过 r 改变字面值 0,这显然是不行的。

(2) 合法。这里对 p2 的类型进行解读,从右向左看,p2 是一个 const 类型,这说明我们无法对 p2 的值进行修改,接下来看到 *,说明它是一个指针,最后看到 int,说明它是一个指向 int 的一个指针。综合来看,p2是一个无法更改指向int 指针类型。注意这里的无法更改指向的涵义,我没有说是不能更改它所指对象的值,也就是说,你可以用 p2 来更改它所指向对象的值,比如 *p2 = 2; 这是完全合法的。但是,你无法更改 p2 本身的值,因为它是 const 类型的,即 p2 = &i3; 是非法的。

(3) 合法。这次 r 就是一个常量引用,就可以拿来引用一个字面值了。

(4) 合法。这里对 p3 的类型进行解读,从右向左看,p3 是一个 const 类型,这说明我们无法对 p3 的值进行修改,接下来看到 *,说明它是一个指针,最后看到 const int,说明它是一个指针,指向一个 const int 类型,这就意味着我们无法通过 p3 来对它指向的对象进行修改。这样,p3 完完全全就是一个只读的对象了,你无法对其就行修改,也无法对其指向的对象进行修改。

(5) 合法。继续按照上面 2 和 4 提到的从右向左方法来解读这个指针。p1 是一个指针,指向的是一个 const int 对象,也就是我们无法通过 p1 来对所指的对象进行修改。但是这里的 i2 并没有提是不是 const 类型,这不冲突吗?答案是肯定的,就是不冲突。用 2.4.2 节中的 Tip 来回答这个问题最好不过了:

Pointers and references to const as pointers or references “that think they point or refer to const.”

也就是说指针以为它指向的是一个 const 类型,所以它自我约束不通过自己改变所指向对象的值,但实际上所指向的对象是不是 const 的并不一定的。因此,下面的代码段是完全合法的:

1
2
3
int i2 = 1;
const int *p1 = &i2; // 此时 *p1 的值为 1
i2 = 2; //此时 *p1 的值为 2

(6) 非法。继续从右向左读,r2 是一个 const 类型的变量,读到这里这道题就知道答案了:既然是 const 类型,那么必须对其进行初始化,这里并没有,因此非法。

(7) 合法。这里 i2 是一个 const int 类型的变量,定义它的时候将 i 的值拷贝给它即可。r 是一个 const int 类型的引用,还是上面说的,这个引用本身已为它引用的对象是一个 const 的,因此它自我约束不通过自己改变 i 的值,但是实际上 i 是可以通过其他途径修改的。