C++ Primer 学习笔记(第四章:表达式)
2019独角兽企业重金招聘Python工程师标准>>>
##C++ Primer 学习笔记(第四章:表达式)
[TOC]
###4.1 基础
左值和右值:
当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。 一个重要的原则是在需要右值的地方可以用左值来代替,但是不能把右值当成左值(也就是位置)使用。当一个左值被当成右值使用时,实际使用的是它的内容(值)。使用
decltype
的时候,如果表达式的求值结果是左值,decltype
作用于该表达式得到一个引用类型。p
的类型是int*
,而*p
会生成左值,多以decltype(*p)
会得到引用int &
。 因为取地址会生成右值,所以decltype(&p)
的结果是int**
。对于那些没有指定执行顺序的运算符来说,如果表达式指向并修改了同一个对象(或者执行了IO任务),将会引发错误并产生未定义的行为。例如:
int i = 0;
cout << i << " " << ++i << endl;
有4种运算符明确规定了运算对象的求值顺序:逻辑与&&
(先求左侧,左侧为真再求右侧)、逻辑或||
、条件运算符?:
、逗号运算符,
。
###4.2 算术运算符
整数相除的结果还是整数,如果有小数部分直接弃除。 结果为负的商统一向0取整,即直接切除小数部分。
参与取模运算
%
的运算对象必须是整数。 表达式(m/n)*n+m%n
的结果与m
相同,即m%n
如果不等于0,则它的符号应该和m相同。
-21 % -8; // -5 -21 / -8; //221 % -5; //1 21/ -5; //-4
###4.3 逻辑关系和运算符
短路求值: 逻辑与(
&&
):当且仅当左侧运算为真时才对右侧进行求值; 逻辑或(||
):当且仅当左侧运算为假时才对右侧进行求值。进行比较运算时除非比较的对象时布尔类型,否则不要使用布尔字面值
true
if (val == true) {/*...*/} //只有当val等于1时条件才为真
###4.4 赋值运算符
- 如果赋值运算符的左右两个运算对象类型不同,则右侧运算对象将转换成左侧运算对象的类型。
int k = 3.14159;
- C++11允许使用花括号括起来的初始值列表作为赋值语句右侧对象。
k = {3.14};
vector<int> vi = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- 把赋值语句放到条件中的用处:(赋值语句的优先级比较低)
while ((i = get_value()) != 42){//其他处理
}
###4.5 递增和递减运算符
关于前置和后置
++
运算符。 除非必须,否则不用递增递减运算符的后置版本。(因为对于复杂的迭代器类型,后置需要将原始值存储下来,可能涉及到额外的消耗。)混用解引用和递增运算符。
auto pbeg = v.begin();
while (pbeg != v.end() && *pbeg >= 0)cout << *pbeg++ << endl;
后置++
的优先级高于解引用运算符,表示得到初始值的副本再递增。 这种*pbeg++
的写法更简洁。
###4.6 成员访问运算符
表达式
ptr->mem
等价于(*ptr).mem
。解引用运算符
*
优先级低于点运算符,所以执行解引用运算的子表达式两端必须加上括号。(*p).size()
。
###4.7 条件运算符(?:
)
cond ? expr1 : expr2
,条件运算符只对expr1
和expr2
中的一个求值。expr1
和expr2
的类型应该相同或者能转换成同一种类型。条件运算符的优先级非常低,因此当一条长表达式中嵌套了条件运算子表达式时,通常需要在它两端加上括号,尤其是在输出表达式中,否则将产生意想不到的效果。
cout << ((grade < 60) ? "fail" : "pass") << endl;
###4.8 位运算符
位运算符作用于整数类型的运算对象,并把运算对象看成是二进制位的集合。
如果运算对象是“小整型”,它的值会被自动提升成较大的整数类型。
移位运算符
>> <<
右侧的运算对象一定不能为负,而且值必须严格小于结果的位数,否则将产生未定义的行为。利用位运算符可以检测位:
unsigned long quiz1 = 0;//32位
quiz1 |= 1 UL << 27;//表示将第27位置成1
quiz1 &= ~(1 UL << 27);//表示将第27位置成0
bool status = quiz1 & (1 UL << 27);//检测第27位
###4.9 sizeof运算符
- sizeof运算符返回一条表达式或一个类型名字所占的字节数,其所得的值是一个
size_t
类型的常量表达式。当返回一个表达式的值时,sizeof expr
并不实际计算其运算对象的值。
int i = 0;
cout << sizeof( i++ ) << endl;//4
cout << i <<endl;//0
sizeof *p
:因为sizeof不会实际求运算对象的值,所以即使p是一个无效的(即未初始化)指针也不会有什么影响。在sizeof
的运算对象中解引用一个无效指针仍然是一种安全的行为,因为指针实际上并没有被真正利用。sizeof Sales_data::revenue
:C++11允许使用作用域运算符来获取类成员的大小。sizeof
运算符无须我们提供一个具体的对象就能访问到类成员,因为要想知道类成员的大小无须真正的获取该成员。sizeof
运算符的结果:char
类型或类型为char
的表达式 引用类型得到被引用对象所占空间的大小 指针类型得到指针本身所占空间大小 对数组执行得到整个数组所占空间大小,等价于所有元素各执行一次,并将结果求和。(而不会把数组当成指针处理) 对string
对象或vector
对象执行只返回类型固定部分的大小,不会计算对象中的元素占用了多少空间。
vector<int> v{0};
cout << sizeof v << endl;//12
- 返回数组元素的数量:
constexpr size_t sz = sizeof(ia) / sizeof(*ia);
int arr2[sz];//正确,sizeof返回一个常量表达式。
###4.10 逗号运算符
- 逗号运算符含有两个运算对象,按照从左向右的顺序依次求值,先对左侧的表达式求值,然后将求值结果丢弃掉,逗号运算符真正的结果是右侧表达式的值。
int i = 1, j = 100;
cout << (i++, j++) << endl;
- 逗号运算符的优先级在最末位。
###4.11 类型转换
算术转换:运算对象将转换成最宽的类型;当表达式中既有浮点型也有整数类型时,整数值将转换成浮点类型。
数组转换成指针:在大多数用到数组的表达式中,数组自动转换成转向数组首元素的指针。当数组用作
decltype
关键字参数,或者作为取地址符(&
)、sizeof
及typeid
等运算符的运算对象时,上述转换不会发生。常量整数值
0
或者字面值nullptr
能转换成任意指针类型;指向任意非常量的指针能转换成void*
;指向任意对象的指针能转换成const void*
转换成常量:能将指向
T
的指针或引用分别转换成指向const T
的指针或引用。但相反的转换不存在。
int i;
const int &j = i;
const int *p = &i;
int &r = j, *q = p;//错误,不允许const转换成常量
- 类类型转换:
string s, t = "a value";//字符串字面值转换成string类型
while (cin >> s)//while的条件部分把cin转换成bool值
强制类型转换:
cast-name<type>(expression)
:其中type
表示转换的目标类型,expression
是要转换的值。如果type
是引用类型,则结果是左值。cast-name
指定了执行的是那种转换,包括static_cast
、dynamic_cast
、const_cast
和reinterpret_cast
中的一种。static_cast
:具有明确定义的类型转换,只要不包含底层const
,都可以使用static_cast
。
double slope = static_cast<double>(j) / i;
当需要把一个较大的算术类型赋值给较小的类型时非常有用,此时意味着告诉编译器不在乎潜在的精度损失,并且不会产生警告。对于编译器无法自动执行的类型转换也很有用,例如可以用来找回存在于void*
指针中的值:(但应当确保转换类型一定正确)
void *p = &d;//任何非常量对象的地址都能存入void*
double *dp = static_cast<double*>(p);
const_cast
:只能改变运算对象的底层const
(常量指针或声明引用的const
),称为去掉const
行为;它只能改变常量属性,不能改变常量类型。
const char *pc;
char *q1 = const_cast<char*>(pc);//正确,但是通过p写值是未定义行为
char *q2 = static_cast<char*>(pc);//错误,static_cast不能转换掉const性质
string s1 = const_cast<string>(pc);//错误,const_cast只转换属性
string s2 = static_cast<string>(pc);//正确,字符串字面值转换为string类型
const_cast
常用于有函数重载(6.4节)的上下文中。
const_cast
的用法不是将一个const变量变成非const
变量的。看一下标准就可以知道,使用const_cast
把一个原本是const的变量转换为非const
,这是一个未定义行为,是非常非常危险的举动。const_cast
的目的,在于某些变量原本不是const
的,但由于某种特殊原因,无意间被变成了const
的,例如使用了一个const
引用指向了一个本来不是const
的对象。结果写了一些代码之后发现它实际上需要被修改。 这在平时的工作中不会遇到因为你可以直接把const
引用修改成非const
的,但C++
中可能的情况太多,尤其考虑到很多复用的时候,有时还是会出现本不该是const
的对象被const
引用了这种情况。尤其是使用模板,比较复杂的情况。这才是const_cast的意义所在。(摘自:求助const_cast的问题(CSDN))
reinterpret_cast
:为运算对象的位模式提供较低层次上的重新解释。
int *ip;
char *pc = reinterpret_cast<char*>(ip);//pc所指的真实对象是一个int而非字符,如果把pc当成普通的字符指针使用就可能在运行时发生错误,例如string str(pc)
使用reinterpret_cast非常危险。使用一个int
的地址初始化pc
,显示地声称这种转换合法,编译器不会报错,但继续使用将引发糟糕的后果。
dynamic_cast
支持运行时类型识别,19.2节介绍。强烈建议避免使用强制类型转换,除了重载函数上下文使用
const_cast
(6.4节)无可厚非,其他情况都应反复斟酌。旧式强制类型转换:
type (expr);//函数形式
(type) expr;//C语言风格
它们与上述三种强制转换有相似行为。
转载于:https://my.oschina.net/u/2359158/blog/494902
C++ Primer 学习笔记(第四章:表达式)相关推荐
- 《Go语言圣经》学习笔记 第四章 复合数据类型
<Go语言圣经>学习笔记 第四章 复合数据类型 目录 数组 Slice Map 结构体 JSON 文本和HTML模板 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. ...
- 机器人导论(第四版)学习笔记——第四章
机器人导论(第四版)学习笔记--第四章 4.1 引言 4.2 解的存在性 4.3 当n<6时操作臂子空间的描述 4.4 代数解法和几何解法 4.5 简化成多项式的代数解法 4.6 三轴相交的Pi ...
- 计算机网络(第7版)谢希仁著 学习笔记 第四章网络层
计算机网络(第7版)谢希仁著 学习笔记 第四章网络层 第四章 网络层 4.3划分子网和构造超网 p134 4.3.1划分子网 4.3.2使用子网时分组的转发 4.3.3无分类编址CIDR(构建超网) ...
- Effective Java(第三版) 学习笔记 - 第四章 类和接口 Rule20~Rule25
Effective Java(第三版) 学习笔记 - 第四章 类和接口 Rule20~Rule25 目录 Rule20 接口优于抽象类 Rule21 为后代设计接口 Rule22 接口只用于定义类型 ...
- 线性代数学习笔记——第四章学习指南——n维向量空间
一.学习内容及要求 1. 内容: §4.1. n维向量空间的概念 线性代数学习笔记--第四十讲--n维向量空间的概念 线性代数学习笔记--第四十一讲--n维向量空间的子空间 §4.2. 向量组的线性相 ...
- Lan Goodfellow 《DEEP LEARNING》学习笔记 --第四章
https://app.yinxiang.com/shard/s64/nl/22173113/a89ab8f8-3937-419c-8b81-cc913abaa35a/ 为了方便起见,我用的可手写的a ...
- python实验题第四章_「Python」2020.03.16学习笔记 | 第四章列表、元组、字典-习题(11-13)...
学习测试开发的Day74,真棒! 学习时间为1H 第四章列表.元组.字典-习题(11-13) 11.求两个集合的交集和并集 代码 list1=[1,2,3,4] list2=[2,3,5,5] def ...
- java email bean_JavaWeb学习笔记-第四章JavaBean技术
第四章 JavaBean技术 4.2.2 使用JavaBean的意义 如果使HTML代码与Java代码相分离,将Java代码单独封装成为一个处理某种业务逻辑的类,然后在JSP页面中调用此类,就可以降低 ...
- 深入理解Linux网路技术内幕学习笔记第四章:通知链
第四章:通知链 内核很多子系统之间具有很强的依赖性,其中一个子系统侦测到的或者产生的事件,其他子系统可能都感兴趣,为了实现这种需求,Linux使用了通知链.通知链只在内核子系统之间使用. 通知链就是一 ...
- 深度之眼 - Python学习笔记——第四章 组合数据类型
第四章 组合数据类型 4.1 列表 列表是可变的! 4.1.1 列表的表达 序列类型:内部元素有位置关系,能通过位置序号访问其中元素 列表是一个可以使用多种类型元素,支持元素的增.删.查.改操作的序列 ...
最新文章
- (转)在Windows平台上安装Node.js及NPM模块管理
- PDF文件合并使用什么工具
- 严重: StandardServer.await: create[8005]:
- 使用可变对象作为Java Map的key,会带来潜在风险的一个例子
- 新浪的股票接口 c#
- UE4 在C++ 动态生成几何、BSP体、BRUSH ---- MESH_GENERATION
- 性能测试--jmeter中http的请求默认值【6】
- 【软件测试】自动化测试到底怎么做(单元测试自动化,接口自动化,UI自动化)
- 最好用AI抠图的软件,方便你,我,他。
- 计算机管理系统有几种,ERP系统有几种?怎么分类
- Python基础之键盘操作
- 利用GDAL根据栅格影像DN值实现颜色渲染
- vue中引入echart图及遇到的问题记录
- 助记词(Mnemonics)生成种子,以及Public Key, Private key
- 微信小程序详解 php,微信小程序canvas基础详解
- html自动关闭当前页面,html如何关闭当前页面
- windows桌面小工具(Tkinter)
- 达内终端端mysql命令_如何从Windows命令行启动MySQL
- 用Javascript开发《三国志曹操传》-开源讲座(二)-人物行走的实现
- 小程序学习从入门到熟练教程
热门文章
- vista——最恰当的中文译名应该是“喂死它”
- python中的tuple_python 数据类型 - tuple
- 8道Python基础面试练习题
- Python批量下载XKCD漫画只需20行命令
- java将0到9随机输出_生成0到9之间的随机整数
- telegraf监控mysql数据库_部署Telegraf+Influxdb+Grafana 架构来监控 MySQL
- C++ 中 inline 用法概述
- 在Linux中如何禁止用户登录
- spring boot2 修改默认json解析器Jackson为fastjson
- 51单片机教程哪个好?