const关键字
const修饰的对象一旦创建后其值就不能再改变,所以const修饰的对象必须初始化
用法:
-
定义常量对象,被const修饰的对象不能被更改
const int i = 42; //正确,编译时初始化 const int j = get_size(); //正确,编译时初始化 const int l; //错误,l未经初始化
-
默认状态下,const对象仅在文件内有效,要想在多个文件直接共享const对象,必须在变量的定义之前添加extern关键字
-
可以把引用绑定到const对象上,我们称之为对常量的引用。对常量的引用不能修改所绑定的对象
const int ci = 1024; const int &r1 = ci; //正确,引用及其引用的对象都是常量 r1 = 2048; //错误,r1是对常量的引用,不能修改 int &r2 = ci; //错误,r2是非常量引用,不能指向一个常量对象
对const的引用可能引用一个并非const的对象
int i = 42; int &r1 = i; //引用r1绑定1 const int &r2 = i; //r2也绑定对象i,但是不允许通过r2改变i的值 r1 = 0; //正确 r2 = 0; //错误
-
和引用一样,可以将指针指向常量或者非常量。同时指针也是对象,因此指针也可以被const修饰。常量指针必须初始化,并且之后它的值就不能再更改了,把*放在const之前表示指针是一个常量
const double pi = 3.14; //pi是一个常量 double *ptr = pi; //错误,普通指针不能指向常量 const double *cptr = π //正确,cptr可以指向一个double的常量 *cptr = 42; //错误,不能给*cptr赋值 int errNumb = 0; int *const curErr = &errNumb; //curErr将一直指向errNumb const double pi = 3.14159; const double *const pip = π //pip是一个指向常量对象的常量指针
-
我们用顶层cost表示任意的对象是常量,底层const则表示指针和引用复合类型的基本类型部分有关
int i = 0; int *const p1 = &i; //不能改变p1的值,顶层const const int ci = 42; //不能改变ci的值,顶层const const int *p2 = &ci; //可以改变p2的值,底层const const int *const p3 = p2; //即是顶层const又是底层const const int &r = ci; //对于引用的声明都是底层const
constexpr关键字
constexpr是C++11新引入的关键字,用来表示常量表达式。常量表达式是指值不会改变,并且在编译过程中就能得到计算结果的表达式。constexpr限定在了编译期就要初始化,const是可以再运行时初始化的。
int foo()
{
return 5;
}
int main()
{
const int p1 = foo(); //正确
constexpr int p2 = foo(); //错误,表达式必须含有常量值,无法调用非 constexpr 函数
}
constexpr只能定义字面值类型,如算术类型,指针和引用。而类似IO库,string类型则不属于字面值类型,也就不能被定义为constexpr。
尽管指针和引用可以被定义为constexpr,但是他们的初始值必须为nullptr或者0,或者是存储于某个固定地址中的对象。
auto和decltype关键字
auto和decltype关键字都可以进行类型推导,可以在编译期就推导出变量或者表达式所属的类型。
-
auto类型说明符:让编译器在编译期通过初始值推算变量的类型。在一条语句声明多个变量时,基础数据类型必须一样
auto i = 0, *p = &i; //正确,i为整型,p为整型指针 auto sz = 0, pi = 3.14; //错误,sz为整型,pi为双精度浮点数
在不声明的情况下,编译器会以引用对象的类型作为auto的类型。
auto也会忽略顶层const,保留底层const
int i = 0, &r = i; auto a = r; //a是int const int ci = i, &cr = ci; auto b = ci; //b是int auto c = cr; //c是int auto d = &i; //d是int* auto e = &ci; //e是一个const int*
-
decltype类型说明符:用于编译器推导表达式类型,表达式并不会进行实际上的运算
decltype(exp) i; //exp可以是表达式,也可以是函数调用,这时候i是表达式的类型或者函数调用的返回值 //其他情况,若exp为左值,decltype(exp)是exp类型的左值引用
与auto不同,对于顶层const的处理不相同
const int ci = 0, &cj = ci; auto x = ci; //x是int decltype(ci) y = ci; //y是const int auto z = cj; //z是int auto az = &cj; //az是const int* decltype(cj) cz = cj; //cz是const int&
当exp是加了括号的变量,结果将是引用
int i = 42; decltype((i)) d; //错误,d是int&,必须初始化 decltype(i) e; //正确,e是未初始化的int