c++ primer 笔记第四章表达式
第四章 表达式
梗概:本章讲解了各种各样的运算符和类型转换。
4.1基础
4.1.1基本概念
一元运算符、二元运算符和三元运算符。运算符是几元由上下文决定。
运算符有优先级结合律和运算对象的求值顺序。
必要时会进行类型转换以及运算符的重载。重载只改变运算对象类型和返回类型。
运算对象分为左值和右值。取地址符结果是右值,前置递加递减得到左值。decltype作用与表达式得到引用类型左值。
4.1.2 优先级和结合律
复合表达式需要考虑优先级和结合律,括号无视优先级和结合律。
练习4.1 105
练习4.2 *(vec.begin()) (*(vec.begin())) +1
4.1.3 求值顺序
int i = f1() * f2()。未定义f1函数和f2函数谁先执行。
规定了运算顺序的运算符有 && || , ?。
求值顺序和符号优先级无关,如 f() + g() * h() + j()中四个函数执行的先后顺序不定。
练习4.3 可以接受,同一表达式中依赖不同操作对象的执行顺序得出结果的情况很少且不必要。
4.2 算术运算符
1: + 正号 - 负号 2: * / % 3: + 加 -减 1,2,3指优先级。
算数运算符作用于任意算术类型,加减与正号可以用于指针。
溢出指计算的结果超出该类型所能表达的范围。
整数相除得整数,取余运算对象是整数,m%n 结果符号和m相同。
练习4.4 (12/3*4) + (5*15) + (24%4/2)
练习4.5 -86 -18 42 -2
4.3 逻辑和关系运算符
逻辑与 和 逻辑或 都执行短路求值的策略,即逻辑与 左侧对象为假则不判断右侧对象, 逻辑或左侧为真则不判断右侧。
循环过程把对象声明成引用可以避免拷贝。
if(val == true) {} ;先把true提升为1再判断,不合理。
练习4.8 相等判断 优先于 逻辑与 优先于 逻辑或
练习4.9 判断cp不是空指针且cp指向的对象不为空串。
4.4 赋值运算符
左侧是可修改的左值。赋值运算符结果即左侧运算对象,且为左值。
右侧对象转化为左侧对象的类型。
初始值列表使赋值对象值初始化。
赋值运算满足右结合律,因此可以连等,但需要类型相同或可转换为相同。
相等判断 == 与赋值运算 = 不可混淆。
复合赋值运算与分开写区别不大。只求值一次。
练习4.13 (a) d=3.0 i = 3 (b) i=3 d=3.5
练习4.14 出错 永远为真且i为42
练习4.15 类型不同且无法转换。 p=0; dval=ival=0;
练习4.16 (a) 加括号 (b) ==
4.5 递增和递减运算符
前置版本与后置版本,前置版本加一后返回作为左值,后置版本同样加一但返回加一前的值的副本作为右值返回。
递增和递减无法保证运算对象的计算顺序,如 a = f(a++) 的结果未定义。
练习4.17 返回结果不同,且一个左值一个右值。
练习4.18 从1开始到结尾出错
练习4.19 (a) ptr 不空指向非0然后ptr+1 (b) 未定义 (c) 未定义
4.6 成员访问运算符
ptr->mem 等价于 (*ptr).mem。注意优先级。
箭头运算符作用域指针对象结果是左值。点运算符结果的左右值与成员所属对象相同。???
练习4.20 (a) 合法 取值后迭代器后移 (b)不合法 string对象不能自增 (c) 不合法,优先级
(d) 合法,判断当前指向字符串是否为空 (e) 不合法,string对象不能自增 (f) 合法
4.7 条件运算符
cond?expr1:expr2; cond为真求值expr1并返回,否则求值expr2返回。
当两个表达式都是左值或能转换为同一类型左值,结果是左值,否则是有值。
条件运算符可以嵌套,一般嵌套2-3层。满足右结合律。
练习4.21
for(auto & x: v)
x = x%2==0?x:2*x;
练习4.22
((grade > 90) ? "high pass" :
grade > 75 ? "pass" :
grade < 60 ? "fail" : "low pass");
练习4.23 加号后面加括号,右括号在最后。
练习4.24 判断第二个问号左边是否为真。 然后判断grade >90是否为真。
4.8 位运算符
右移首位插入可能是符号位,无符号数插入0。
移位运算符满足左结合律,注意优先级。
练习4.25 0xffffe380
练习4.26 uint可能低于32位 ???
练习4.27 (a) 3 (b) 7 (c) true (d) true
4.9 sizeof运算符
sizeof (type) sizeof expr 返回值类型size_t。
sizeof满足右结合律,sizeof操作对象无需有效,如空指针。
对引用类型得到被引用对象大小。
sizeof不会把数组转换为指针。
string对象和vector对象只返回固定占用大小。
练习4.29 10 1
练习4.30 sizeof (x+y) sizeof(p->mem[i]) (c) (sizeof a)<b (d) sizeof(f())
4.10 逗号运算符
从左到右依次求值,最后返回右侧结果。
练习4.32 遍历数组
练习4.33 true返回y+1 false返回y-1
4.11类型转换
表达式运算时可能执行隐式转换。
4.11.1算术转换
算术转换将运算符的运算对象转换成其中最宽的类型。
小于int的转换为int或uint。较大的转换为int系列中最小的。
无符号类型不小于有符号类型时转化为无符号类型,否则依赖机器。
练习4.34 (a) float转bool (b) 先int转float 后float转double (c) 先char转int,后int转double
练习4.35 (a) 先char转int后int转char (b) 先int转float后uint转float
(c) 先ui转float,后float转double (d) 先int转float,后float转double,后double转char
4.11.2其它隐式类型转换
数组转指针,decltype 取地址 sizeof和typeid时不发生。使用引用初始化数组也不发生。
指针转换:0 nullptr 转任意指针。 指向非常量指针转void*,指向任意对象可转向const void*。
类类型定义的转换:字面字符串转string,cin转bool。
4.11.3显式转换
cast-nam<type> (expression)
static_cast dynamic_cast const_cast reinterpret_cast
static_cast 确定类型转换。转换void*指针。
const_cast 改变运算对象的底层const,只改变属性。
reintepret_cast 为运算对象的位模式提供较低层次上的重新解释。
旧式的强制类型转换在不同情况对应不同的cast类型。
建议避免强制类型转换。
练习4.36 i *= static_cast<int> (d);
练习4.37 (a) pv = reintepret_cast<void*> ps; (b) static_cast<int>(*pc);
(c) reintepret_cast<void*>(&d); (d) static_cast<char*>(pv);
练习4.38 把j/i的结果转化为double类型。
上一篇: TP5导入Excel表格
下一篇: 带头节点单链表的基本操作