C++primer第二章2.4节对于const限定符相关内容进行详解
const限定符
- const对象一旦创建后其数值就不会被再次改变,因此const对象必须初始化。
- const对象只在文件中有效
- 在不同的文件中使用不同的const来定义不同的常量,那么每个文件定义的变量只会在自己所属的文件中有效。如果想让多个文件共享同一个const变量,那么使用关键字extern即可
const的引用
把引用绑定到const对象上,就像绑定到其他对象上一样,称之为对于常量的引用。和普通信用不同,对于常量的引用不能被用于修改它所绑定的对象。
const int ci = 1024;
const int &r1 = ci;//正确,引用及其对应的对象都是常量
r1 = 42; //错误,r1是对于常量的引用
int &r2 = ci; //错误,试图让一个非常量去引用一个常量对象
- 因为不允许直接为ci赋值,当然也不可以通过引用去改变ci,因此,对于r2的初始化是错误的,假设初始化合法,就可以通过r2来改变他引用的对象的数值,这显然是不正确的。
初始化和对const的引用
引用的类型必须和其所引用对象的类型是一致的,但是有两个例外。1,初始化常量引用时候允许用任意表达式来作为初始化的数值,只要该表达式结果可以转化为引用的类型即可。尤其,允许一个常量引用绑定非常量的对象、字面值甚至是一个一般表达式。
int i = 42;const int &r1 = i; //允许将const int& 绑定到一个普通int对象上const int &r2 = 42;//r2是一个常量的引用const int &r3 = r1 * 2;//r3是一个常量的引用int &r4 = r1 * 2; //错误,r4是一个普通的非常量的引用
对const引用可能引用一个并非const的对象
常量的引用仅仅对于可以引用可以参与的操作进行了限定,对于引用的对象的本身是不是一个常量未做限定。因为对象也可能是一个非常量,所以可以通过其他途径来改变它的值。
int i = 42;int &r1 = i; //引用r1绑定对象iconst int &r2 = i;//r2也绑定对象i,但是不允许通过r2来修改i的数值r1 = 0; //r1并非常量,i的数值修改为0r2 = 0; //错误,r2是一个常量的引用,因此不可以修改引用的元素的数值
指针和const
- 与引用一样,可以另指针指向常量或者非常量。类似于常量的引用,指向常量的指针不能用于改变其所指对象的数值
- 要想存放常量对象的地址,只能指向常量的指针。
const double pi = 3.141592653; //pi是个常量,它的值不能改变double *ptr = π //错误,ptr是一个普通的指针const double *cptr = π //正确,cptr可以指向一个双精度的常量*cptr = 43;//错误,不能给*cptr赋值
- 指针的类型必须和所指对象类型一致,但是有两个例外:1,允许令一个指向常量的指针指向一个非常量的对象。
double dval = 3.14;//dval是一个双精度的浮点数,它的数值可以改变
cptr = &dval; //正确,但是不能通过cptr来改变dval的数值
const指针
指针是对象而引用不是,因此就像其他对象类型一样,允许把指针本身定位常量。常量指针必须初始化,而且一旦初始化,它的值(存放在指针中的那个地址)就不可以再改变了。
把*放在const关键字之前用来说明指针是一个常量,即不变的是指指针本身的数值而不是指向的那个值
int errNum = 0;int *const curErr = &errNum; //curErr一直指向errNumconst double pi = 3.14158;const double *const pip = π //pip是一个指向常量对象的常量指针
- 遵循从右往左读的思想
- 离curErr最近的符号是const,意味着curErr本身是一个常量对象,对象的类型由声明符的其余部分决定。声明符的下一个符号是*,意思是curErr是一个常量指针。同理,pip是一个常量指针,指向的对象是一个双精度浮点类型的常量。
- 指针本身是一个常量并不意味着不能通过指针修改其所指向的数值,能否这样做完全依赖于所指向的对象的类型。例如,如果pip是一个指向常量的常量指针,不论是pip所指的对象值还是pip自己存储的那个地址都不能改变。如果,curErr指向的是一个一般的非常量整数,那么完全可以用curErr来修改errNum的数值。
顶层const
- 指针本身是一个对象,它又可以指向另外一个对象,因此,指针本身是不是常量以及指针所指的是不是一个常量,是两个相互独立的问题。用名词顶层const表示指针本身是一个常量;而使用名词底层const来表示指针所指的对象是一个常量。
- 顶层的const可以表示任意的对象是常量,这一点适用于任何数据类型,如算数类型、类、指针等。底层const则与指针和引用等符合类型的基本类型部分相关。
- 比较特殊的是,指针类型既可以是顶层const也可以是底层const,这一点和其他类型相比区别比较明显。
int i = 0;int *const p1 = &i; //不可以改变p1的数值,这是一个顶层的constconst int ci = 42; //不可以改变ci的数值,这是一个顶层的constconst int *p2 = &ci; //可以改变p2的数值,这是一个底层的constconst int *const p3 = p2; //靠右边的是顶层const,靠左边的是底层的constconst int &r = ci; //用于声明的const都是底层const
- 底层const限制不可以忽视。执行对象的拷贝操作的时候,拷入和烤出的对象具有相同的底层const资格,或者两个对象的数据类型之间能够相互转化,一般来说非常量可以转化为常量,反之不可以。
constexper和常量表达式
- 常量表达式是指不会改变并且在编译的过程中能得到编译结果的表达式。显然,字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。
- 一个对象或者表达式是不是常量表达式是由它的数据类型和初始值共同决定的。
const int max_files = 20; //max_files是常量表达式const int limit = max_files + 1; //limit是常量表达式int staff_size = 27;//staff_size不是常量表达式const int sz = get_size();//sz不是常量表达式
- staff_size的初始值是一个字面值常量,但是由于他的数据类型只是一个普通的int而不是const int,所以他不属于常量表达式。
- sz本身是一个常量,但是他的具体值直到运行的时候才可以获取到,因此也不是常量表达式。
constexpr变量
- C++11允许将变量声明为constexpr类型,从而使得编译器来验证变量的数值是否是一个常量的表达式。
- 声明为constexpr的变量一定是一个常量,而且需要用常量表达式来初始化。
constexpr int mf = 20; //20是常量表达式constexpr int limit = mf + 1 ;// limit是常量表达式constexpr int sz = size();// 只有当size是一个constexpr函数的时候,才是一条正确的声明语句
字面值类型
- 常量表达式的值需要在编译的时候就得到计算,因此对声明constexpr时用到的类型必须有所限制。因为这些类型一般比较简单,值也比较明显,将其称之为字面值类型。
- 算数类型、引用和指针都是属于字面值类型。自定义的类型、IO库、string则不属于字面值类型,即不可以定义为constexpr。
- 指针和引用可以被定义为constexpr类型,但是他们的初始值会受到严格的限制,constexpr指针的初始值必须是nullptr或者是0,或者是存储于某个固定地址中的对象。
- 先前指出函数体内部定义的变量一般来说不会存在到固定的地址中,因此constexpr指针不可以指向这种变量。相反,因为存储于函数体外的对象其固定的地址不变,因此可以用于初始化constexpr指针。
- 其中,允许函数定义一类有效范围超出函数本身的变量,这类变量和定义在函数体之外的变量一样也有固定的地址,因此也可以用于对于constexpr指针的初始化。
指针和constexpr
- 在constexpr声明中定义了一个指针,限定符号constexpr仅仅对于指针有效,而对于指针所指向的对象本身无效。
const int *p = nullptr;//p是一个指向整型常量的指针constexpr int *q = nullptr;//q是一个指向整数的常量指针
- 与其他常量指针相类似,constexpr指针既可以指向一个常量指针,也可以指向一个非常量
const int *np = nullptr;//np是一个指向整数的常量指针,其值为空
int j = 0;
constexpr int i = 42;//i的类型是整型常量
//i和j必须定义在函数体之外constexpr const int *p = &i;//p是常量指针,指向整型常量iconstexpr int *p1 = &j;
C++primer第二章2.4节对于const限定符相关内容进行详解相关推荐
- 第二章作业题2-链表-计算机17级(期末复习带详解版)
解析在后面 这次的题关于循环链表和双向链表的部分真的很难,不会的不少,我再想想吧 p1-1: 链表访问节点的时间复杂度为O(N) p1-3: 时间复杂度为O(1),如果是两个链表都是有序的,合成一个有 ...
- 传热学环肋肋效率matlab程序,传热学 第二章第四节 通过肋片的导热.pdf
传热学 第二章第四节 通过肋片的导热 第四节 通过肋片的导热 第二章 导热基本定律及稳态导热 传热 学 第一节 导热基本定律 (Heat Transfer ) 第二节 导热微分方程式 (Heat Tr ...
- 第二章 第四节:替换和切割
Python基础入门(全套保姆级教程) 第二章 第四节:替换和切割 strip() 去掉字符串左右两端的空白符(空格, \t, \n) s = " 你好, 我叫 周杰伦 " s1 ...
- 谈谈在计算机系统中引入操作系统,初中信息技术第一册第二章第1节《操作系统简介》教学设计...
广州市初中信息技术第一册第二章第1节<操作系统简介>教学设计 一.学习者分析 学生通过第一章的学习,对计算机的软.硬件知识有了初步的了解,同时对操作系统的作用也有了简单的认识.但由于学生普 ...
- C++primer :const限定符
1.问题引入 <span style="font-size:18px;"><span style="font-size:18px;">f ...
- 计算机软件硬件的会计处理,重庆会计从业考试《会计电算化》第二章第四节计算机软件...
2014年重庆会计从业资格考试备考工作已经开始,中华会计网校为了帮助参加2014年重庆会计从业资格考试的学员巩固知识,提高备考效果,整理了会计从业资格考试复习资料供大家参考,希望对广大考生有所帮助,祝 ...
- 第二章 第4节——块元素
4.块元素 块元素:无论宽度大小,始终会占据页面中它高度范围内的那一整行空间,不会与其他元素共享.同时你可以任意控制块元素的宽高度,内填充等.常见的块元素有div,p,ul,li,h1~h6系列标签等 ...
- 【重识云原生】第二章计算第一节——计算虚拟化技术总述
云平台计算领域知识地图: 楔子:计算虚拟化技术算是云计算技术的擎天之柱,其前两代技术的演进一直引领着云计算的发展,即便到了云原生时代,其作用依然举足轻重. 一.计算虚拟化技术总述 1.1 虚拟化技 ...
- 第二章:第一节数据清洗及特征处理-自测
回顾&引言]前面一章的内容大家可以感觉到我们主要是对基础知识做一个梳理,让大家了解数据分析的一些操作,主要做了数据的各个角度的观察.那么在这里,我们主要是做数据分析的流程性学习,主要是包括了数 ...
最新文章
- SAP MM 不常用事务代码MIDO
- Neutron — Hierarchical Port Binding(层次化端口绑定)
- lucene源码分析(7)Analyzer分析
- oracle的imp和exp
- ethercard php_关于EtherCard的webClient代码分析
- S3C2440中断跳转分析
- SharePoint Web Service系列: Add或Update其他各种类型的项
- 微分方程建模——以传染病模型为例
- 什么叫反向链接?什么是死链接?什么是错误链接?
- 专注于Win7系统清除附带推广和工具
- OSChina 周三乱弹 —— 谈什么对象?睡什么觉?
- JSD-2204-Vue-ElementUI-Day06
- 农村科学实验杂志农村科学实验杂志社农村科学实验编辑部2022年第12期目录
- 不用计算机怎么算根号二,根号怎么打 根号2或3等于多少?
- 大数据时代物联网技术发展前景与应用分析
- CE简单修改演示(植物大战僵尸)
- 2014苹果全球开发者大会:新系统成主角 无硬件发布
- 免费的python教程资源(中文,英文都有)
- 局域网内共享vmware虚拟机
- power supply框架
热门文章
- dio设置自定义post请求_Flutter Dio简单二次封装和自定义Header
- c++界面开发_QT开发(三)——GUI原理分析
- postgis创建空间数据库(pgadmin4)
- 【转】!C#中的Stream相关
- 使用Nuget 安装指定版本package或者更新package到指定版本
- TUN/TAP设备浅析(二) -- TUN/TAP的编程
- PWN-PRACTICE-BUUCTF-15
- 国密算法SM2-java实现
- 【HihoCoder - 1550】顺序三元组(思维)
- 使用java开发应用程序_使用Java中的插件支持开发应用程序