const对象的初始化
const对象必须初始化,初始值可以是任意复杂的表达式,如果用一个对象初始化另外一个对象,则他们是不是const都无关紧要。
int i = 42;
const int ci = i; //正确
int j = ci; //正确
const对象被设为仅在文件内有效。当多个文件中出现了同名的const变量时,其实等同于在不同文件中分别定义了独立的变量。
但是如果要在一个文件中定义const,而在其他多个文件中声明并使用它也可以,只要对const变量不管是声明还是定义都添加extern关键字。下面是例子:
main.cpp
#include
using namespace std;
extern const int n;
int main()
{
cout << n << endl;
return 0;
}
test.cpp
extern const int n = 100;
如果去掉了test.cpp中的extern,编译就会出错。
引用绑定到const对象上,称为对常量的引用,简称“常量引用”。
定义和初始化:
const int ci = 1024;
const int &r1 = ci; //引用及其对应的对象都是常量
r1 = 42; //错误,对常量的引用不能用于修改他所绑定的对象
int &r2 = ci; //不能用非常量引用指向常量对象
const int &r3 = 42; //正确,r3是一个常量引用,可以为常量引用绑定字面值,但是不可以为普通引用绑定字面值
const int &r4 = r1 * 42; //正确,r4是一个常量引用,用表达式初始化
前面引用那一节提到,引用类型必须和其所引用的类型一致,但是有例外。第一种例外就是:
允许为一个常量引用绑定非常量对象,但是不允许通过这个引用修改对象的值。例如:
int i = 42;
const int &r = i;// 正确,允许把一个const int&绑定到普通int上
r = 0; //错误,绑定可以,但是不能通过r修改i的值
想存放常量对象的地址,只能用指向常量的指针,但是不能给绑定的对象赋值。
const double pi = 3.14
double *ptr = π //错误,不能用普通指针指向const
const double *cptr = π //正确
*cptr = 42; //错误,不能给*cptr赋值
和引用一样,指针类型必须和其所绑定的对象类型一致,这里也有例外。第一种例外就是:
允许让一个指向常量的指针指向一个非常量对象,但是不允许通过这个指针修改对象的值。例如:
double dval = 3.14;
const double *cptr = &dval; //正确,但是不能通过cptr改变dval的值
*cptr = 42; //错误,绑定可以,但不能通过cptr修改dval的值
指针本身可以是常量。常量指针必须初始化,一旦初始化完成就不能改了。不变的是指针本身而不是指针指向的对象。表示方式是*写在const前面。
int errNumb = 0;
int *const curErr = &errNumb; //curErr指向errNumb
const double pi = 3.14159;
const double *const pip = π //pip是指向常量对象的常量指针
指针是常量不代表什么,能否通过指针修改其所指对象的值,取决于所指对象的类型。
顶层const
顶层const表示指针本身是个常量,底层const表示指针所指的对象是一个常量。
int i = 0;
int *const p1 = &i; //顶层const
const int ci = 42;
const int *p2 = &ci; //底层const
const int *const p3 = p2; //左边是底层const,右边的是顶层const
const int &r = ci; //用于声明引用的const都是底层const
执行对象的拷贝操作,顶层const和底层const不同。其中顶层const不受影响。但是,常量的底层const不能赋给非常量的底层const
constexpr和常量表达式
常量表达式:(1)类型是const(2)编译过程就能得到计算结果(3)用常量表达式初始化的const对象也是常量表达式
const int max_files= 20; //是常量表达式
const int limit = max_files + 1; //是常量表达式
int staff_size = 27; //不是const,不是常量表达式
const int sz = get_size(); // 运行时才能知道值,不是常量表达式
有时候是不是常量表达式很难分辨,所以C++11允许将变量声明为constexpr类型,让编译器来验证变量的值是否是一个常量表达式。
constexpr int mf = 20;
constexpr int limit = mf + 1;
constexpr int sz = size(); //只有当size是一个constexpr函数时才是一条正确的声明语句
constexpr函数必须足够简单,使得编译时就可以计算其结果。
字面值类型可以是:算数类型,引用和指针。其中指针初始值只能是nullptr或0,或者存储于某个固定地址中的对象(所有函数体之外的对象或static类型对象)。
constexpr float x = 42.0;
constexpr int *q = nullptr; //一个constexpr指针的初始值必须是nullptr或者0,或者是存储于某个固定地址中的对象
constexpr指针
指针初始值只能是nullptr或0,或者存储于某个固定地址中的对象(所有函数体之外的对象或static类型对象)。constexpr可以指向常量,也可以指向非常量。
而且constexpr仅对指针有效,与指针所指对象无关。constexpr只修饰指针。
const int *p = nullptr; //指向整型常量的指针
constexpr int *q = nullptr; //指向整数的常量指针。constptr把它所定义的对象设置为顶层const
constexpr int *np = nullptr;
int j = 0;
constexpr int i = 42;
//i和j必须定义在所有函数之外
constexpr const int *p = &i; //常量指针,指向整型常量i
constexpr int *p1 = &j; //常量指针,指向整型j