因为没有系统的学过 C++,最近在开发过程中反反复复被引用和指针摩擦,索性系统地跟着 「C++ Primer」一书好好整理了下相关知识。
预备知识
引用
- 引用属于复合类型,为所引用的对象取了别名;
- 引用本身不是对象,引用指向某个对象;
- 一旦初始化完成,引用将和它的初始值对象一直绑定在一起;
指针
- 指针属于复合类型,存放某个对象的内存地址;
- 指针本身就是一个对象(在内存中有自己的存储地址),作用是指向另一个对象,以方便调用所指向的对象;
- 如果修改了指针本身(即所存储的内存地址),自然就改变了它所指向的对象;
引用与指针的结合使用
- 引用本身不是对象,所以不能定义「指向引用的引用」或「指向引用的指针」;
- 指针本身是一个对象,所以可以定义「指向指针的指针」和「指向指针的引用」;
const 限定符
- const 对象一旦创建后,其值就不能再改变;
- 如果 const 关键词用于基本类型的变量,其用意就是变量的值不会被改变;
- 如果 const 关键词和复合类型变量(例如指针或引用)一起使用,「复合类型变量本身是不是常量」和「其所指向的值是不是变量」,就是两个独立的问题。
常量引用 (reference to const)
- 常量引用为约定的叫法,完整含义是一个「指向 const 对象的引用」;
const int ci = 1024;
const int &r1 = ci; //引用的类型必须和与之绑定的对象严格匹配
- 根据 const 的定义,r1 所指向的值(即 ci)不能通过 r1 改变(反过来想,如果可以通过 r1 改变 ci 的值, const 关键词的使用毫无意义);
- 常量引用所指向的对象,不一定是常量,可以通过其他途径改变其值。例如:
int i = 42;
int &r1 = i;
const int &r2 = i;
r2 = 0; //不合法,不能通过 r2 去改变 i 的值;
r1 = 0; //合法,r1 是普通引用
指向常量的指针(pointer to const)
- 与常量引用类似,pointer to const 所指向的对象,不一定是常量,可以通过非 const 对像去改变其值;
double pi = 3.14;
const double *r1 = π
double *r2 = π
*r1 = 0; // 不合法,不能通过 r1 修改 pi 的值;
*r2 = 0; // 合法,r2 是普通指针;
- 与引用不同,指针本身就是一个对象,所以 pointer to const 本身的值是可以被改变的(当然改变后就指向了其他对象);
const pointer
- 译为常量指针,但是与常量引用不同,它的定义是「指针本身为常量」,不变的是指针本身(即其所表示的内存地址)而非指向的那个值。
- const pointer 只能保证指针本身是常量,但不能说明其指向的对象是否为常量:
int errNumb = 0;
int *const curErr = &errNumb; // curErr 是 const pointer, 但指向了普遍变量 errNumb,curErr 可以去修改 errNumb 的值;
const double pi = 3.14159;
const double *const pip = π // pip 指向了一个 const 对象,所以不能通过 pip 去改变 pi 的值;
注意:常量指针中,const 起到类型符的作用,声明了一个常量。而在常量引用中,const 是类型修饰符,去修饰引用符。
小结
当 const 关键词与指针和引用结合使用时:
- 使用 pointer to const 与 reference to const 时,编译器自认为它们指向的是 const 对象,所以不能通过它们去修改其所指向的对象的值。但其实允许它们指向一个非 const 对象,也就允许通过其他途径修改所指向对象的值;
- Pointer to const 的特殊之处在于,它本身的值是可以改变的。所以它既不能保证自己的值不被改变,也不保证其所指向的值不能改变,只能保证不通过这个指向常量的指针去改变所指向的对象的值;
- Const pointer 只能保证自己的值(内存地址)不能改变。与 pointer to const 或 reference to const 不同的是,允许通过这个指针去改变所指向的值(如果所指向的是不是常量的话)。
