先简单回忆一下常量的性质:
int main() { const int buffSize = 512; buffsize = 512; //× buffSize是常量 }初始化时:
const int i = get_val(); //√ 运行时初始化 const int j = 42; //√ 编译时初始化 const int k; //× k未经初始化当用一个对象去初始化另外一个对象,他们是不是const就无关紧要
int i = 42; const int ci = i; int j = ci;ci是整形常量,但ci的常量特征仅仅在执行 改变ci 的操作时才会发挥作用
const和引用# 对常量的引用#把引用绑定到const对象上,称之为对常量的引用
对常量的引用不能用作修改它所绑定的对象,引用 及其 引用的对象 都是常量
const int ci = 1024; const int &r1 = ci;需要注意的是:
const int ci = 1024; const int &r1 = ci; r1 = 42; //× r1是对常量的引用 int &r2 = ci; //× r2是一个非常量引用,ci是一个常量对象因为不允许把ci用作修改它所绑定的对象,所以也不能通过引用去改变ci(假设第四句合法,那我们就可以通过r2去改变ci了,显然是不对的)
以下两句同理
int &r3 = r1; //× const int &r4 = r1; //√我们口头所说的常量引用其实是对const的引用,严格来说是不存在常量引用的,因为和指针不一样,引用不是对象,我们没有办法让引用本身很定不变
(P.S:由于C++不允许随意改变引用所绑定的对象,所以也可以理解为,所有的引用都是常量,当然了,引用的对象是否是常量,会决定其所能参与的操作,但无论如何也不会影响到引用和对象的绑定关系)
初始化对常量的引用#我们知道引用的类型必须要和所引用的对象类型一致,但涉及初始化常量的引用会出现第二种例外(第一种:初始化常量引用是允许用任意表达式作为初始值,只要该表达式能转换成引用的类型)
int i = 42; const int &r1 = i; //√ 允许const int绑定到一个普通int对象上 const int &r2 = 42; //√ r2是一个常量引用 const int &r3 = r1 * 2; //√ r3是一个常量引用 int &r4 = r1 * 2; //× r4是一个普通的非常量引用为什么会出现这种情况?先来看一个简单的例子
double dval = 0.114514; const int &ri = dval; cout << "ri = " << ri <<endl;运行输出
ri=0
在这个过程中,其实是编译器把代码改成了:
double dval = 0.114514; const int temp = dval; const int &ri = temp; cout << "ri = " << ri <<endl;这种情况下,ri绑定了一个临时量对象,这下你可看懂上面的代码发生了什么了吧
你可以想象以下,如果ri不是常量时,执行了上述初始化过程会带来怎样的后果:如果ri不是常量。就允许对ri赋值,这样就会改变ri所引用对象的值(此时绑定的是临时量而非dval),所以C++也把以下这种行为归为非法
double dval = 0.114514; int &ri = dval; //× cout << "ri = " << ri <<endl;同时注意,对const的引用可能引用一个并非const的对象
对const的引用仅对引用可参与的操作做出了限定,对于引用对象本身是否是一个常量没有做出限定,因此对象也可能是个非常量,允许通过其他途径改变它的值
int i = 42; int &r1 = i; const int &r2 = i; //r2 = 0; //× r2是一个常量引用 cout << "r2 = " << r2 <<endl; i = 0; cout << "r2 = " << r2 <<endl;该程序输出如下:
r2 = 42
r2 = 0
类似于对常量的引用,指向常量的指针不能用于改变其所指对象的值
同时,想要存放常量对象的地址,只能使用指向常量的指针:
const double homo = 1.14; double *ptr = &homo; //× ptr是一个普通指针 const double *cptr = &homo; //√ cptr = 5.14 //× 不能给*cptr赋值不同于引用,我们能改变指向常量的指针所指向的对象
const double homo = 1.14; const double *cptr = &homo; cout << "cptr = " << *cptr <<endl const double homo2 = 5.14; cptr = &homo2; cout << "cptr = " << *cptr <<endl; //允许一个 指向常量的指针 指向 一个非常量对象注意,与引用类似,虽然我们说指针的类型必须与所指对象一致,但是这里有第一种例外:允许一个指向常量的指针指向一个非常量对象
const double homo = 1.14; const double *cptr = &homo; double dval = 3.14; cptr = &dval; //允许一个 指向常量的指针 指向 一个非常量对象 *cptr = 0.0 //但是不允许通过 指向常量的指针 修改非常量对象的值