由于项目需要转过来学习C++,结果第一天就被const卡的云里雾里。为了彻底搞清楚const到底是个什么鬼,决定为它单独写一篇博客进行记录,也作为我学习C++的第一篇博客。
是什么
定义
const是用来对变量的类型加以限定来让变量不能改变的限定符。
特点
与非const类型所能参与的操作相比,const类型的对象能完成其中大部分,但也不是所有的操作都合适。主要的限制就是只能在const类型的对象上执行不改变其内容的操作。
初始化
由于const类型的值一旦定义就无法更改,所以需要在定义时就给const类型的值赋值。
作用范围
编译器将在编译过程中把用到该变量的地方都替换成对应的值。
默认情况下,const对象被设定为仅在文件内有效。当多个文件中出现了同名的const变量时,其实等同于在不同文件中分别定义了独立的变量。如果要在一个文件中定义const而在其他多个文件中声明并使用它,需要对const变量不管是声明还是定义都添加extern关键字,这样只需定义一次就可以了。
转载请注明出处:http://blog.csdn.net/ylbs110/article/details/50811425
const指针和引用
const引用
与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象。
初始化和对const的引用
初始化常量引用时允许用任意表达式作为初始值,只要改表达式的结果能转换成应用的类型即可。尤其,允许为一个引用绑定非常量的对象、字面值、甚至是个一般表达式。
Int i=1;
const int &r1=I;
const int &r2=1;//r2如果是非常量则不能这么引用
const int &r3=r1*2;
对const的引用可能引用一个并非const的对象
常量引用进队引用可参与的操作做出了限定,对于引用对象本身是不是一个常量未做限定。也就是可以通过直接改变所引用对象的值来改变引用的值。
const指针
const指针有两种:
指向常量的指针:即指针指向的对象是常量。不能用于改变其所指对象的值,要想存放常量对象的地址,只能使用指向常量的指针。
常量指针:即指针本身是常量,它所指向的地址无法修改。指针式对象而引用不是,因此就像其他对象类型一样,允许把指针本身定位常量。常量指针必须初始化。
把放在const关键字之前用以说明指针是一个常量,即指针所指向的地址不能变;放在const之后类型之前说明指针所指向的对象是一个常量。
顶层const和底层const
关于顶层const和底层const,这一篇分析的不错:
https://segmentfault.com/q/1010000002568358/a-1020000002573278
顶层const(*在const前):表示指针本身是个常量
底层const(*在const后):表示指针所指的对象是一个常量
C++ 的世界里:
- POD,类对象都只能是”自身”,所以只能是顶层const。
- 指针可以是自身(指针本身),可以是别人(指向别人)。所以指针既可以是顶层const,又可以是底层const。
- 引用没有自身,只能是别人(引用是别名)。所以引用只能是底层const。
当执行对象的拷贝操作时,拷入和拷出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换。一般来说,非常量可以转换成常量,反之则不行。
对于指针:
- 底层const可以修改指针的指向,也就是更换指针所指向的对象,但无法修改指针所指向的对象的内容。
- 顶层const可以修改指针所指向对象的内容,但是无法修改指针的指向。
对于引用:
作为只能是底层const的引用,它无法修改它所指向的对象的内容,但同时由于引用本身的特性限制了它一旦绑定了一个值再无法修改,所以它也无法修改它所指向的对象。
这就是引用作为底层const的同时还保留了顶层const的特质的原因。
constexpr和常量表达式
常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。字面值属于常量表达式,而常量表达式初始化的const对象也是常量表达式。
constexpr变量
C++新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化。
字面值类型
算数类型、引用和指针都属于字面值类型。自定义类,IO库、string等类型则不属于字面值类型。
一个constexpr指针的初始值必须是nullptr或者0,或者是存储于某个固定地址中的对象。
指针和constexpr
在constexpr声明中如果定义了一个指针,限定符constexpr仅对指针有效。constexpr把它所定义的对象设置为了顶层const。
处理类型
类型别名
typedef char *pstring;
const pstring cstr = 0; //char *const cstr
const pstring *ps; //char *const *ps
其中
const pstring cstr
和pstring const cstr
完全相等,都相当于char *const cstr
。
原因:
Pstring是char*,是一个指针,const修饰pstring相当于修饰指针。而又由于const修饰指针的时候应该是顶层const,所以是char *const cstr
。
auto
auto一般会忽略掉顶层const,同时底层const则会保留下来。如果希望推断出的auto类型是一个顶层const,需要明确指出:
const auto f=ci;
根据上面对引用的顶层const和底层cosnt的解释,auto推断出的const值的引用将会保留底层const,但同时拥有顶层const的特质。
decltype
decltype处理顶层const和引用的方式与auto有些许不同。如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内)。