Table of Contents:

总之就是一句话:尽可能多用 const,让代码更安全。

 一般用法

const int MAXNUM = 100; 
由于常量一旦被创建后其值就不能再改变,所以常量必须在定义的同时赋值(初始化),后面的任何赋值行为都将引发错误。
By Default, const Objects Are Local to a File,在编译的时候就已经被替换了。所有作用域是当前文件。

int n = 90;
const int MaxNum1 = getNum(); //运行时初始化
const int MaxNum2 = n; //运行时初始化
const int MaxNum3 = 80; //编译时初始化

 const和指针,判别时用就近原则

const int *p1;     //指向常量的指针
int * const p3;    //常量指针

 const 和非 const 类型转换

const char *char *是不同的类型,不能将const char *类型的数据赋值给char *类型的变量。但反过来是可以的,编译器允许将char *类型的数据赋值给const char *类型的变量。
这种限制很容易理解,char *指向的数据有读取和写入权限,而const char *指向的数据只有读取权限,降低数据的权限不会带来任何问题,但提升数据的权限就有可能发生危险。

 编译器会为const引用创建临时变量

将常引用绑定到临时数据时,编译器采取了一种妥协机制:编译器会为临时数据创建一个新的、无名的临时变量,并将临时数据放入该临时变量中,然后再将引用绑定到该临时变量。注意,临时变量也是变量,所有的变量都会被分配内存。

 C++const 和 引用

不同类型的数据占用的内存数量不一样,处理方式也不一样,指针的类型要与它指向的数据的类型严格对应。
引用(Reference)和指针(Pointer)在本质上是一样的,引用仅仅是对指针进行了简单的封装,类型严格一致这条规则同样也适用于引用。
但给引用添加 const 限定后,不但可以将引用绑定到临时数据,还可以将引用绑定到类型相近的数据,这使得引用更加灵活和通用,它们背后的机制都是临时变量。

 const 和函数形参

const形参好处:
1. 使用 const 可以避免无意中修改数据的编程错误;
2. 清楚的分清参数的输入和输出特性
3. 可以接受const和非const的变量,否则将只能接收非 const 类型的实参
4. 使用 const 引用能够让函数正确生成并使用临时变量,可以将引用绑定到类型相近的数据,而不仅仅是严格匹配

size_t strlen ( const char * str );

 C++ const成员变量和const成员函数(常成员函数)

const 成员变量的用法和普通 const 变量的用法相似,只需要在声明时加上 const 关键字。初始化 const 成员变量只有一种方法,就是通过构造函数的初始化列表

我们通常将 get 函数设置为常成员函数。读取成员变量的函数的名字通常以get开头,后跟成员变量的名字,所以通常将它们称为 get 函数。
需要强调的是,必须在成员函数的声明和定义处同时加上const 关键字。char *getname() constchar *getname()是两个不同的函数原型,如果只在一个地方加 const 会导致声明和定义处的函数原型冲突

 函数开头的 const 用来修饰函数的返回值,表示返回值是 const 类型,也就是不能被修改,例如const char * getname()
 函数头部的结尾加上 const 表示常成员函数,此时的const是修饰的this指针,这种函数只能读取成员变量的值,而不能修改成员变量的值,例如char * getname() const

 C++ const对象(常对象)

const class object(params);
只能调用类的const成员(包括 const 成员变量和 const 成员函数)了

 C++11 constexpr:验证是否为常量表达式

常量表达式,是由多个(≥1)常量组成的表达式。常量表达式一旦确定,其值将无法修改。
我们知道,C++ 程序的执行过程大致要经历编译、链接、运行这 3 个阶段。值得一提的是,常量表达式和非常量表达式的计算时机不同,非常量表达式只能在程序运行阶段计算出结果;而常量表达式的计算往往发生在程序的编译阶段,这可以极大提高程序的执行效率,因为表达式只需要在编译阶段计算一次,节省了每次程序运行时都需要计算一次的时间。

对于用 C++ 编写的程序,性能往往是永恒的追求。那么在实际开发中,如何才能判定一个表达式是否为常量表达式,进而获得在编译阶段即可执行的“特权”呢?除了人为判定外,C++11 标准还提供有 constexpr 关键字。
constexpr 关键字的功能是使指定的常量表达式获得在程序编译阶段计算出结果的能力,而不必等到程序运行阶段。C++ 11 标准中,constexpr 可用于修饰普通变量、函数(包括模板函数)以及类的构造函数。

 注意,获得在编译阶段计算出结果的能力,并不代表 constexpr 修饰的表达式一定会在程序编译阶段被执行,具体的计算时机还是编译器说了算。

 C++11 constexpr和const的区别

在C++ 98之前const是有两种语义的:1.只读 2.常量
C++ 11标准中,为了解决 const 关键字的双重语义问题,保留了 const 表示“只读”的语义,而将“常量”的语义划分给了新添加的 constexpr 关键字。因此 C++11 标准中,建议将 const 和 constexpr 的功能区分开,
 即凡是表达“只读”语义的场景都使用 const,
 表达“常量”语义的场景都使用 constexpr。

只读”和“常量”之间并没有必然的联系

int main()
{
    int a = 10;
    const int & con_b = a; //只读,但并不意味着值为常量。
    cout << con_b << endl;
    a = 20;
    cout << con_b << endl;
}

程序中用 const 修饰了 con_b 变量,表示该变量“只读”,即无法通过变量自身去修改自己的值。但这并不意味着 con_b 的值不能借助其它变量间接改变,通过改变 a 的值就可以使 con_b 的值发生变化。