2019独角兽企业重金招聘Python工程师标准>>>

##C++ Primer 学习笔记(第四章:表达式)


[TOC]


###4.1 基础

  1. 左值和右值:
    当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。 一个重要的原则是在需要右值的地方可以用左值来代替,但是不能把右值当成左值(也就是位置)使用。当一个左值被当成右值使用时,实际使用的是它的内容(值)。

  2. 使用decltype的时候,如果表达式的求值结果是左值,decltype作用于该表达式得到一个引用类型。 p的类型是int*,而*p会生成左值,多以decltype(*p)会得到引用int &。 因为取地址会生成右值,所以decltype(&p)的结果是int**

  3. 对于那些没有指定执行顺序的运算符来说,如果表达式指向并修改了同一个对象(或者执行了IO任务),将会引发错误并产生未定义的行为。例如:

int i = 0;
cout << i << " " << ++i << endl;

有4种运算符明确规定了运算对象的求值顺序:逻辑与&&(先求左侧,左侧为真再求右侧)、逻辑或||、条件运算符?:、逗号运算符,


###4.2 算术运算符

  1. 整数相除的结果还是整数,如果有小数部分直接弃除。 结果为负的商统一向0取整,即直接切除小数部分。

  2. 参与取模运算%的运算对象必须是整数。 表达式(m/n)*n+m%n的结果与m相同,即m%n如果不等于0,则它的符号应该和m相同。

 -21 % -8; // -5        -21 / -8; //221 % -5; //1           21/ -5; //-4

###4.3 逻辑关系和运算符

  1. 短路求值: 逻辑与(&&):当且仅当左侧运算为真时才对右侧进行求值; 逻辑或(||):当且仅当左侧运算为假时才对右侧进行求值。

  2. 进行比较运算时除非比较的对象时布尔类型,否则不要使用布尔字面值true

if (val == true) {/*...*/} //只有当val等于1时条件才为真

###4.4 赋值运算符

  1. 如果赋值运算符的左右两个运算对象类型不同,则右侧运算对象将转换成左侧运算对象的类型。
int k = 3.14159;
  1. C++11允许使用花括号括起来的初始值列表作为赋值语句右侧对象。
k = {3.14};
vector<int> vi = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  1. 把赋值语句放到条件中的用处:(赋值语句的优先级比较低)
while ((i = get_value()) != 42){//其他处理
}

###4.5 递增和递减运算符

  1. 关于前置和后置++运算符。 除非必须,否则不用递增递减运算符的后置版本。(因为对于复杂的迭代器类型,后置需要将原始值存储下来,可能涉及到额外的消耗。)

  2. 混用解引用和递增运算符。

auto pbeg = v.begin();
while (pbeg != v.end() && *pbeg >= 0)cout << *pbeg++ << endl;

后置++的优先级高于解引用运算符,表示得到初始值的副本再递增。 这种*pbeg++的写法更简洁。


###4.6 成员访问运算符

  1. 表达式ptr->mem等价于(*ptr).mem

  2. 解引用运算符*优先级低于点运算符,所以执行解引用运算的子表达式两端必须加上括号。(*p).size()


###4.7 条件运算符(?:

  1. cond ? expr1 : expr2,条件运算符只对expr1expr2中的一个求值。expr1expr2的类型应该相同或者能转换成同一种类型。

  2. 条件运算符的优先级非常低,因此当一条长表达式中嵌套了条件运算子表达式时,通常需要在它两端加上括号,尤其是在输出表达式中,否则将产生意想不到的效果。

cout << ((grade < 60) ? "fail" : "pass") << endl;

###4.8 位运算符

  1. 位运算符作用于整数类型的运算对象,并把运算对象看成是二进制位的集合。

  2. 如果运算对象是“小整型”,它的值会被自动提升成较大的整数类型。

  3. 移位运算符>> <<右侧的运算对象一定不能为负,而且值必须严格小于结果的位数,否则将产生未定义的行为。

  4. 利用位运算符可以检测位:

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运算符

  1. sizeof运算符返回一条表达式或一个类型名字所占的字节数,其所得的值是一个size_t类型的常量表达式。当返回一个表达式的值时,sizeof expr并不实际计算其运算对象的值。
int i = 0;
cout << sizeof( i++ ) << endl;//4
cout << i <<endl;//0
  1. sizeof *p:因为sizeof不会实际求运算对象的值,所以即使p是一个无效的(即未初始化)指针也不会有什么影响。在sizeof的运算对象中解引用一个无效指针仍然是一种安全的行为,因为指针实际上并没有被真正利用。

  2. sizeof Sales_data::revenue:C++11允许使用作用域运算符来获取类成员的大小。sizeof运算符无须我们提供一个具体的对象就能访问到类成员,因为要想知道类成员的大小无须真正的获取该成员。

  3. sizeof运算符的结果: char类型或类型为char的表达式 引用类型得到被引用对象所占空间的大小 指针类型得到指针本身所占空间大小 对数组执行得到整个数组所占空间大小,等价于所有元素各执行一次,并将结果求和。(而不会把数组当成指针处理) 对string对象或vector对象执行只返回类型固定部分的大小,不会计算对象中的元素占用了多少空间。

vector<int> v{0};
cout << sizeof v << endl;//12
  1. 返回数组元素的数量:
constexpr size_t sz = sizeof(ia) / sizeof(*ia);
int arr2[sz];//正确,sizeof返回一个常量表达式。

###4.10 逗号运算符

  1. 逗号运算符含有两个运算对象,按照从左向右的顺序依次求值,先对左侧的表达式求值,然后将求值结果丢弃掉,逗号运算符真正的结果是右侧表达式的值。
int i = 1, j = 100;
cout << (i++, j++) << endl;
  1. 逗号运算符的优先级在最末位。

###4.11 类型转换

  1. 算术转换:运算对象将转换成最宽的类型;当表达式中既有浮点型也有整数类型时,整数值将转换成浮点类型。

  2. 数组转换成指针:在大多数用到数组的表达式中,数组自动转换成转向数组首元素的指针。当数组用作decltype关键字参数,或者作为取地址符(&)、sizeoftypeid等运算符的运算对象时,上述转换不会发生。

  3. 常量整数值0或者字面值nullptr能转换成任意指针类型;指向任意非常量的指针能转换成void*;指向任意对象的指针能转换成const void*

  4. 转换成常量:能将指向T的指针或引用分别转换成指向const T的指针或引用。但相反的转换不存在。

int i;
const int &j = i;
const int *p = &i;
int &r = j, *q = p;//错误,不允许const转换成常量
  1. 类类型转换:
string s, t = "a value";//字符串字面值转换成string类型
while (cin >> s)//while的条件部分把cin转换成bool值
  1. 强制类型转换: cast-name<type>(expression):其中type表示转换的目标类型,expression是要转换的值。如果type是引用类型,则结果是左值。cast-name指定了执行的是那种转换,包括static_castdynamic_castconst_castreinterpret_cast中的一种。

  2. static_cast:具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast

double slope = static_cast<double>(j) / i;

当需要把一个较大的算术类型赋值给较小的类型时非常有用,此时意味着告诉编译器不在乎潜在的精度损失,并且不会产生警告。对于编译器无法自动执行的类型转换也很有用,例如可以用来找回存在于void*指针中的值:(但应当确保转换类型一定正确)

void *p = &d;//任何非常量对象的地址都能存入void*
double *dp = static_cast<double*>(p);
  1. 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))

  1. reinterpret_cast:为运算对象的位模式提供较低层次上的重新解释。
int *ip;
char *pc = reinterpret_cast<char*>(ip);//pc所指的真实对象是一个int而非字符,如果把pc当成普通的字符指针使用就可能在运行时发生错误,例如string str(pc)

使用reinterpret_cast非常危险。使用一个int的地址初始化pc,显示地声称这种转换合法,编译器不会报错,但继续使用将引发糟糕的后果。

  1. dynamic_cast支持运行时类型识别,19.2节介绍。

  2. 强烈建议避免使用强制类型转换,除了重载函数上下文使用const_cast(6.4节)无可厚非,其他情况都应反复斟酌。

  3. 旧式强制类型转换:

type (expr);//函数形式
(type) expr;//C语言风格

它们与上述三种强制转换有相似行为。

转载于:https://my.oschina.net/u/2359158/blog/494902

C++ Primer 学习笔记(第四章:表达式)相关推荐

  1. 《Go语言圣经》学习笔记 第四章 复合数据类型

    <Go语言圣经>学习笔记 第四章 复合数据类型 目录 数组 Slice Map 结构体 JSON 文本和HTML模板 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. ...

  2. 机器人导论(第四版)学习笔记——第四章

    机器人导论(第四版)学习笔记--第四章 4.1 引言 4.2 解的存在性 4.3 当n<6时操作臂子空间的描述 4.4 代数解法和几何解法 4.5 简化成多项式的代数解法 4.6 三轴相交的Pi ...

  3. 计算机网络(第7版)谢希仁著 学习笔记 第四章网络层

    计算机网络(第7版)谢希仁著 学习笔记 第四章网络层 第四章 网络层 4.3划分子网和构造超网 p134 4.3.1划分子网 4.3.2使用子网时分组的转发 4.3.3无分类编址CIDR(构建超网) ...

  4. Effective Java(第三版) 学习笔记 - 第四章 类和接口 Rule20~Rule25

    Effective Java(第三版) 学习笔记 - 第四章 类和接口 Rule20~Rule25 目录 Rule20 接口优于抽象类 Rule21 为后代设计接口 Rule22 接口只用于定义类型 ...

  5. 线性代数学习笔记——第四章学习指南——n维向量空间

    一.学习内容及要求 1. 内容: §4.1. n维向量空间的概念 线性代数学习笔记--第四十讲--n维向量空间的概念 线性代数学习笔记--第四十一讲--n维向量空间的子空间 §4.2. 向量组的线性相 ...

  6. Lan Goodfellow 《DEEP LEARNING》学习笔记 --第四章

    https://app.yinxiang.com/shard/s64/nl/22173113/a89ab8f8-3937-419c-8b81-cc913abaa35a/ 为了方便起见,我用的可手写的a ...

  7. python实验题第四章_「Python」2020.03.16学习笔记 | 第四章列表、元组、字典-习题(11-13)...

    学习测试开发的Day74,真棒! 学习时间为1H 第四章列表.元组.字典-习题(11-13) 11.求两个集合的交集和并集 代码 list1=[1,2,3,4] list2=[2,3,5,5] def ...

  8. java email bean_JavaWeb学习笔记-第四章JavaBean技术

    第四章 JavaBean技术 4.2.2 使用JavaBean的意义 如果使HTML代码与Java代码相分离,将Java代码单独封装成为一个处理某种业务逻辑的类,然后在JSP页面中调用此类,就可以降低 ...

  9. 深入理解Linux网路技术内幕学习笔记第四章:通知链

    第四章:通知链 内核很多子系统之间具有很强的依赖性,其中一个子系统侦测到的或者产生的事件,其他子系统可能都感兴趣,为了实现这种需求,Linux使用了通知链.通知链只在内核子系统之间使用. 通知链就是一 ...

  10. 深度之眼 - Python学习笔记——第四章 组合数据类型

    第四章 组合数据类型 4.1 列表 列表是可变的! 4.1.1 列表的表达 序列类型:内部元素有位置关系,能通过位置序号访问其中元素 列表是一个可以使用多种类型元素,支持元素的增.删.查.改操作的序列 ...

最新文章

  1. (转)在Windows平台上安装Node.js及NPM模块管理
  2. PDF文件合并使用什么工具
  3. 严重: StandardServer.await: create[8005]:
  4. 使用可变对象作为Java Map的key,会带来潜在风险的一个例子
  5. 新浪的股票接口 c#
  6. UE4 在C++ 动态生成几何、BSP体、BRUSH ---- MESH_GENERATION
  7. 性能测试--jmeter中http的请求默认值【6】
  8. 【软件测试】自动化测试到底怎么做(单元测试自动化,接口自动化,UI自动化)
  9. 最好用AI抠图的软件,方便你,我,他。
  10. 计算机管理系统有几种,ERP系统有几种?怎么分类
  11. Python基础之键盘操作
  12. 利用GDAL根据栅格影像DN值实现颜色渲染
  13. vue中引入echart图及遇到的问题记录
  14. 助记词(Mnemonics)生成种子,以及Public Key, Private key
  15. 微信小程序详解 php,微信小程序canvas基础详解
  16. html自动关闭当前页面,html如何关闭当前页面
  17. windows桌面小工具(Tkinter)
  18. 达内终端端mysql命令_如何从Windows命令行启动MySQL
  19. 用Javascript开发《三国志曹操传》-开源讲座(二)-人物行走的实现
  20. 小程序学习从入门到熟练教程

热门文章

  1. vista——最恰当的中文译名应该是“喂死它”
  2. python中的tuple_python 数据类型 - tuple
  3. 8道Python基础面试练习题
  4. Python批量下载XKCD漫画只需20行命令
  5. java将0到9随机输出_生成0到9之间的随机整数
  6. telegraf监控mysql数据库_部署Telegraf+Influxdb+Grafana 架构来监控 MySQL
  7. C++ 中 inline 用法概述
  8. 在Linux中如何禁止用户登录
  9. spring boot2 修改默认json解析器Jackson为fastjson
  10. 51单片机教程哪个好?