1. 顶层const(top-level const)与底层const(low-level const)
为了更好的研究指针和引用,我们引入了底层const这个名词。注意,底层const是针对C++里面的指针和引用而引入的。
我们知道,指针本身是不是常量与该指针所指向的是不是常量,这是两个相互独立的问题。为了区分这两种情况,我们引入两个专有名词:顶层const(top-level const)与底层const(low-level const)。用 顶层const(top-level const)表示指针本身是一个常量,而用 底层const(low-level const)表示指针所指的对象是一个常量。由指针引入,更一般的,顶层const可以表示任意的对象(任何数据类型)是常量。而底层const则与指针和引用等复合类型的基本类型部分有关。
为了检验一下有没有正确理解什么是顶层const(top-level const)与底层const(low-level const),请看几个小例子:
int i = 0;
int *const p1 = &i; //不能改变p1的值,因为p1是一个顶层const
const int ci = 1; //不能改变ci的值,因为ci是一个顶层const
const int *p2 = &ci; <span style="white-space:pre"> </span>//允许改变p2的值,因为p2是一个底层const
const int * const p3 = p2; <span style="white-space:pre"> </span>//靠左的是底层const,靠右的const是顶层const
const int &r = ci; //用于声明引用的const都是底层const,因为引用本身就是一个顶层const,只能在初始化的时候进行赋值
对于拷贝操作,顶层const没有什么要求,而底层const要求左值必须比右值更严格。
- 拷贝操作时,对于顶层const,可以把一个顶层const值赋给一个非顶层const变量,也可以把一个非顶层const值初始化给一个顶层const值。如上面例子中:
int *const p1 = &i; //把一个非顶层const值初始化给一个顶层const值
i = ci; //变量ci是顶层const,但变量i不是顶层const
p2 = p3; //变量p3是顶层const,但变量p2不是顶层const
- 拷贝操作时,对于底层const,左值必须和右值相同或更严格。也就是说,对于指针和引用,如果右值是const,则左值必须是底层const。还是上面的例子:
int *p = p3; //error:p3包含底层const,而p没有
p2 = p3; //正确:p2与p3都是底层const
p2 = &i; //正确:int*能转换成const int*
int &r = ci; //error:r只具有顶层const而不具有底层const,而ci具有底层const
const int &r2 = i; //正确:可以把普通变量赋给const int&
需要注意的一点:对于常量对象取地址,得到的也是一种底层const
const int ci = 0;
const int* iptr = &ci; //正确:iptr与右值具有同样的底层const
int* iptr2 = &ci; //error:对于常量对象取地址,得到的也是一种底层const
2. const形参与函数重载
对于函数调用,和其他初始化过程一样,当用实参初始化形参时,会忽略掉形参的顶层const。这句话的意思也就是说,如果想通过顶层const进行函数重载,是不会通过编译的。函数重载机制会自动假装忽略掉顶层const而保留底层const。
也就是说:
void func(const int i);
void func(int i);
编译器认为这是同一个函数,而不是函数重载,进而报错|error: redefinition of 'void func(int)'|。
这个例子告诉我们,一个拥有顶层const的形参无法和另一个没有顶层const的形参区分开来。
但是,我们可以通过底层const来进行函数重载。
Record lookup(Account&); //函数作用于Account引用
Record lookup(const Account&); //新函数,函数作用于常量Account引用
Record lookup(Account*); //新函数,函数作用于指向Account的指针
Record lookup(const Account*); //新函数,函数作用于指向Account常量的指针
当然,当我们传递一个非常量对象或者指向非常量对象的指针时,编译器会优先选用非常量版本的函数。