四、const与引用
  我们知道,引用必须在定义的时候赋值,这样会所引用的变量绑定在一起并作为它的一个别名,在程序中的其他地方,是不能让引用再与其他对象绑定。这个特性,让引用看起来像是const对象一样,一旦定义后将不能更改。所以并不存在const的引用。
  但是我们却可以引用一个const的对象(变量),我们称之为对常量的引用,与普通的引用不同的时,对常量的引用不能被用作修改它所绑定的对象。
  1 const int ci = 1024;
  2 const int &r1 = ci;
  3 r1 = 42; // Error:r1是对常量的引用
  4 int & r2 = ci; //Error:不能将一个非常量引用指向一个常量的对象
  我们知道,引用的类型必须与其所引用对象的类型一致,如下面的代码:
  double dval = 3.14;
  int& ri = dval; // Error:无法用double类型的值初始化int&类型的引用(非常量限定)
  上述代码为何不行?
  此处ri引用了一个int型的整数。对于ri的操作数应该是整数运算,但是dval却是一个双精度的浮点数而非整数。因此为了确保让ri绑定一个整数,编译器把上述代码变成了如下形式:
  double dval = 3.14;
  int temp = dval;
  int& ri = temp;
  其中temp是一个临时变量,而ri绑定了一个临时量,所以当ri改变时,并没有改变davl的值,所以这种引用是无效的。
  也许你注意到了,当我们把double变量绑定在一个int&类型上时,编译器提示后有个括号:非常量限定。这说明如果是一个常量的引用,则有可能是通过的,显然下面的代码没有任何问题:
  double dval = 3.14;
  const int& ri = dval;
  因为在这里,ri是一个常量引用,我们并不想通过ri改变dval的值,只要能读到dval对应的int型的值行。
  五、const与指针
  我们知道,指针与引用不同,指针本身是一个对象,所以存在常量指针,这种指针在定义并初始化后,便不能再指向其他变量。用来修饰这种常量指针的const,我们称之为"顶层const"。
  与顶层指针对应的是底层指针,这种指针指向一个const修改的对象,这一点上有点像是常量的引用。
  对于指向常量的指针或引用,都有以下规则:
  1)可以将一个非const对象的地址赋给一个指向const对象的指针
  2)可以将一个非const对象的地址赋给一个指向非const对象的指针
  3)可以将一个const对象的地址赋给一个指向const对象的指针
  4)不可以将一个const对象的地址赋给一个指向非const对象的指针。

 

1 int var;
2 const int ci = 42;
3
4 int *p1 =& var;
5 int *p2 = &ci; // Error,const int* 不能用于初始化int*
6 const int *p3 = &var; //ok
7 const int *p4 = &ci; // ok

 

  还有一种指向const对象的const指针,这种指针首先表明,本身是一个const指针,一旦初始化后不能指向其他对象;其次,它本身所指向的对象也是一个常量,即不能通过指针修改对象的值。
  const int var = 42;
  const int* const p = &var;
  这里再强调一点,const只是给编译器看的,我们可以很轻松的骗过编译器,并看看编译器都做了什么:
  1 const int var = 42;
  2 int* p = (int*)&var;
  3 *p = 20;
  4 cout << var << endl;     //42
  5 cout << *p << endl;     //20
  我们在代码的第2行,用一个类型转换强制的,把一个非const指针指向了一个const对象。
  但是后面我们通过这个指针来修改这个值,却没有生效,原因呢?
  那是因为编译器在编译阶段发现var是一个常量,所以在编译目标代码时已经将var的地方都用42进行了替换。
  六、const与类
  其实类定义的对象,与普通的变量是一样的,用const修饰时,说明这个类是一个常量类对象,这个对象有下面2个特点:
  1)不能改变其成员变量(非mutalbe成员)
  2)不能调用其非const成员函数

 


1 class AClass{
2     public:
3         int m_var;
4         mutable int m_mutable_var;
5         void setVar(int var){ m_var = var; }
6         void printVar(){ cout << m_var; }
7         void printVar_const()const { cout << m_var; }
8     };
9
10     const AClass ac;
11     ac.m_var = 20; // Error:ac是一个const类,不能修改成员变量
12     ac.m_mutable_var = 42; // ok 可以修改mutable修饰的变量
13     ac.setVar(20); // Error: ac不能调用非const成员函数,而且这个成员函数还修改了成员变量的值
14     ac.printVar();// Error:ac不能调用非const成员函数
15     ac.printVar_const(); // ok