重读C++ Primer——第四章笔记

目录

0、表达式的定义

1、函数调用也是一种特殊的运算符,它对运算对象的数量没有限制。

2、左值和右值

2.1、与decltype的关系

3、优先级、结合律与求值顺序

4、整数除法

5、除非必要,否则不使用递增递减运算符的后置版本

6、剪头运算符作用于一个指针,返回一个左值。点运算符返回左值还是右值由成员所属对象的左右值属性决定。

7、sizeof运算符

8、整型提升

9、类型转换是发生在表达式中的,所以应该可以把类型转换理解为表达式的一种属性。类型转换大量发生在表达式求值的时候,在对引用赋值时会涉及到,参见第二章笔记第九条。

10、const_cast

11、用户定义类型转换

11.1类型转换的级别


0、表达式的定义

表达式由一个或多个运算对象组成,可以对运算对象求值以得到一个结果。可以使用运算符组合多个运算对象组成一个复杂的表达式。

1、函数调用也是一种特殊的运算符,它对运算对象的数量没有限制。

函数调用就是将调用运算符作用于一个表达式,这个表达式是函数或函数指针。调用表达式的类型就是函数的返回类型。进一步,函数调用也是一个表达式。

字面值和变量是最简单的表达式,其结果就是字面值和变量的值。

另外,一个变量加上括号时编译器就把它当做表达式,见第二章笔记第四条。

变量可以看做一个只有运算对象而没有运算符的表达式(497-498)。

2、左值和右值

当对象被用作右值的时候,用的是对象的值(内容);当被用作左值时,用的是对象的身份(在内存中的位置)。

上面i*42就是一个右值,因为它根本就没有地址,而且是一个表达式。

内置类型和迭代器的递增递减运算符作用于左值运算对象,其前置版本得到的结果也是左值。

取地址符作用于左值对象,得到指向这个对象的指针,这个指针是一个右值。

下面来自第十三章笔记第15.1条:

返回左值引用的函数,连同赋值、下标、解引用、前置递增/递减运算符都是返回左值的表达式;返回非引用类型的函数,连同算术、关系、位运算自己后置递增/递减运算符都是返回右值的表达式。只能将右值引用或const的左值引用绑定到它们身上。

比较左值和右值,可以发现两者的不同:左值有持久的状态,而右值要么是字面值常量、要么是表达式求值过程中创建的临时量。(497页)

2.1、与decltype的关系

如果表达式的数值结果是一个左值,decltype作用于这个表达式(不是作用于变量)得到一个引用类型,如p是int*,则decltype(*p)得到int&;另一方面,取地址运算符得到一个右值,所以decltype(&p)得到int**。

3、优先级、结合律与求值顺序

优先级和结合律是用来描述多个运算符出现在同一个表达式中时运算对象的组合方式的,而求值顺序是用来描述某一个运算符周围的运算对象是按照什么顺序(如先左后右)求值的。

4、整数除法

c++11规定如果两个操作数符号不相同,结果一律向0去整(即直接舍弃小数部分)。

根据取余运算的定义,(m/n)*n+m%n的结果与m相等,这句话的含义整体上可以如下理解:余数就是整数除法得到的商与被除数之间的距离,因为C++11规定整数除法求商不论商是正还是负数,一律向0取整,所以这个商一定是比被除数更靠近数轴上的0点的,那这个余数就必须与m的符号一致才能使得商加上余数等于被除数。

5、除非必要,否则不使用递增递减运算符的后置版本

因为后置版本需要将原始值存储下来以将其返回,这会带来不必要的开销;而前置版本直接将对象改变后返回对象本身。

6、剪头运算符作用于一个指针,返回一个左值。点运算符返回左值还是右值由成员所属对象的左右值属性决定。

7、sizeof运算符

运算对象有两种形式

sizeof (type)
sizeof expr

第一种是针对一种类型,包括内置类型和类类型,第二种是针对表达式,包括字面量和变量都是(最简单的)表达式,两者不要用混了。

目录

0、表达式的定义

1、函数调用也是一种特殊的运算符,它对运算对象的数量没有限制。

2、左值和右值

2.1、与decltype的关系

3、优先级、结合律与求值顺序

4、整数除法

5、除非必要,否则不使用递增递减运算符的后置版本

6、剪头运算符作用于一个指针,返回一个左值。点运算符返回左值还是右值由成员所属对象的左右值属性决定。

7、sizeof运算符

8、整型提升

9、类型转换是发生在表达式中的,所以应该可以把类型转换理解为表达式的一种属性。类型转换大量发生在表达式求值的时候,在对引用赋值时会涉及到,参见第二章笔记第九条。

10、const_cast

11、用户定义类型转换

11.1类型转换的级别


 

这个运算符的最重要特点就是它不会实际计算其运算对象的值且满足右结合律。表达式sizeof *p即使p是一个无效(即未初始化)的指针,也不会报错,因为sizeof不会真正地解引用这个指针。此外sizeof和解引用操作符*的优先级一样,且满足右结合律,所以求的是解引用后对象的大小。

sizeof作用于数组返回整个数组占用空间的大小,这意味着它不会把数组转换成指针。它的返回值是一个常量表达式。所以可以用来定义数组(367页)

8、整型提升

算数类型转换时,小整型会被提升成大整型,转换时先考虑有符号整型类型,再考虑无符号整型类型。提升的第一个“档位”就是int,即如果char和short遇到一起,它们都被提升成int,而不是把char提升成short。

算数转换会把表达式中涉及到的类型转换成最宽的,由上可以看出无符号类型比相应的有符号类型更“宽”一些,所以同时出现两种类型且

1)无符号类型(的值)不小于有符号类型。后者将转换为前者,如果后者是一个负数,则转换结果为这个负数加上无符号类型所能表达的数值个数,即负数加上无符号类型的模。(60页)

2)如果有符号类型大于无符号类型,结果将取决于机器。

9、类型转换是发生在表达式中的,所以应该可以把类型转换理解为表达式的一种属性。类型转换大量发生在表达式求值的时候,在对引用赋值时会涉及到,参见第二章笔记第九条。

10、const_cast

const_cast不仅能去掉cast属性,也能加上const属性。(235页)

11、用户定义类型转换

(总结性结论来自第541页第14.9节)

编译器一次只能执行一个用户定义的类型转换,且隐式的类型转换可以置于内置的类型转换之前或之后。例子来自于540页。

SmallInt si;

上述的转换顺序是如何的?(167页)

那si + 3为何是把si转换成int而不是反过来呢?大概是因为这是一个算术运算表达式,所以运算对象都要先转换为算术类型。下面的例子也能作为印证

11.1类型转换的级别

(245页6.6.1节)

编译器将聪实参类型到形参类型的转换分为以下几个级别

其中,算术类型转换对整型之间来说会转换成最宽的类型(如果有符号数和无符号数同时存在,则前者会转换成后者,参见本笔记第8条,转换规则见第二章笔记第7条);整型和浮点同时存在会转换成浮点数。

在对不同的转换路径的精确度进行比较时,如果在某个高优先级别得到了结果,则不会再判断底优先级别(例子来自于545页14.9节)

当使用用户定义的转换之前或之后存在标准转换,则标准转换将决定最佳匹配是哪个。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值