表达式
基础
左值和右值
左值表达式的求值结果是一个对象或者一个函数,然而以常量对象为代表的某些左值实际上不能作为赋值语句的左侧运算对象。
当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)
赋值运算符需要一个(非常量)左值作为其左侧运算对象,得到的结果也仍然是一个左值
取地址符作用于一个左值运算对象,返回一个指向该运算对象的指针,这个指针是一个右值
内置解引用运算符、下标运算符、迭代器解引用运算符、string 和 vector 的下标运算符的求值结果都是左值
内置类型和迭代器的递增运算符作用于左值运算对象,其潜质版本所得的结果也是左值
算术运算符
算数运算符(左结合律) | ||
---|---|---|
运算符 | 功能 | 用法 |
+ | 一元正号 | + expr |
– | 一元负号 | – expr |
* | 乘法 | expr * expr |
/ | 除法 | expr / expr |
% | 求余 | expr % expr |
+ | 加法 | expr + expr |
– | 减法 | expr – expr |
一元运算符的优先级最高,接下来是乘法和除法,优先级最低的是加法和减法
逻辑和关系运算符
逻辑和关系运算符 | |||
---|---|---|---|
结合律 | 运算符 | 功能 | 用法 |
右 | ! | 逻辑非 | !expr |
左 | < | 小于 | expr < expr |
左 | <= | 小于等于 | expr <= expr |
左 | > | 大于 | expr > expr |
左 | >= | 大于等于 | expr >= expr |
左 | == | 相等 | expr == expr |
左 | != | 不相等 | expr != expr |
左 | && | 逻辑与 | expr && expr |
左 | 逻辑或 | expr expr |
逻辑与运算符和逻辑或运算符都是先求左侧运算对象的值再求右侧运算对象的值,当且仅当左侧运算对象无法确定表达式的结果时才会计算右侧运算对象的值。这种策略称为 短路求值
赋值运算符
赋值运算符满足右结合律,且优先级较低,优先级低于关系运算符优先级
递增和递减运算符
两个版本:前置版本和后置版本
前置版本:先将运算对象加 1(减 1),然后将改变后的对象作为求值结果
后置版本:求值结果为运算对象改变前的那个值,之后将运算对象加 1(减 1)
后置运算符的优先级高于解引用运算符
成员访问运算符
分为点运算符和箭头运算符,解引用运算符的优先级低于点运算符
条件运算符
形式为:
cond ? expr1 : expr2;
cond 是判断条件的表达式,expr1 和 expr2 是两个类型相同或可能转换为某个公共类型的表达式
首先执行 cond 的值,如果条件为真则对 expr1 求值并返回该值,否则对 expr2 求值并返回该值
条件运算符满足右结合律
cout << ((grade < 60) ? "fail" : "pass"; // 输出 pass 或者 fail
cout << (grade < 60) ? "fail" : "pass"; // 输出 0 或者 1
cout << grade < 60 ? "fail" : "pass"; // 错误:试图比较 cout 和 60
位运算符
位运算符(左结合律) | ||
---|---|---|
运算符 | 功能 | 用法 |
~ | 位求反 | ~expr |
<< | 左移 | expr1 << expr2 |
>> | 右移 | expr1 >> expr2 |
& | 位与 | expr & expr |
^ | 位异或 | expr ^ expr |
位或 | expr expr |
左移运算符(<<)在右侧插入值为 0 的二进制位,右移运算符(>>)的行为依赖左侧运算对象的类型,如果该运算对象是无符号类型,在左侧插入值为 0 的二进制位,如果运算对象是带符号类型,在左侧插入符号位的副本或值为 0 的二进制位
位求反运算中,char 类型的运算对象首先提升为 int 类型,提升时运算对象原来的位保持不变,往高位添加 0 即可
移位运算符满足左结合率
sizeof 运算符
返回一条表达式或一个类型名字所占的字节数,满足右结合律,所得值为 size_t 类型的常量表达式
两种形式:
sizeof (type)
sizeof expr
对 char 或者类型为 char 的表达式执行 sizeof 运算,结果得 1
对引用类型执行 sizeof 运算符得到被引用对象所占空间的大小
对指针执行 sizeof 运算得到指针本身所占空间的大小
对解引用指针执行 sizeof 运算得到指针指向的对象所占空间的大小,指针不需有效
对数组执行 sizeof 运算得到整个数组所占空间的大小,等价于对数组中所有的元素各执行一次 sizeof 运算并将所的结果求和
对 string 对象或 vector 对象执行 sizeof 运算只返回该类型固定部分的大小,不会计算对象中的元素占用了多少空间
逗号运算符
按照从左向右的顺序依次求值,逗号运算符真正的结果是右侧表达式的值
类型转换
隐式转换
在大多数表达式中,比 int 类型小的整型值首先提升为较大的整数类型
在条件中,非布尔值转换成布尔类型
初始化过程中,初始值转换成变量的类型;在赋值语句中,右侧运算对象转换成左侧运算对象的类型
如果算术运算或关系运算的运算对象有多种类型,需要转换成同一种类型
函数调用时,也会发生类型转换
算数转换
把一种算数类型转换成另外一种算数类型
整型提升:把小整数类型转换成较大的整数类型
如果一个运算对象是无符号类型,另一个运算对象是带符号类型,而且其中的无符号类型不小于带符号类型,那么带符号类型的运算对象转换成无符号类型的
如果带符号类型大于无符号类型,则转换结果依赖于机器
数组转换成指针
转换成布尔类型
转换成常量
类类型转换
显示转换
强制类型转换形式:
cast-name<type>(expression);
type 是转换的目标类型,expression 是要转换的值 cast-name 是 static_cast、dynamic_cast、const_cast 和 reinterpret_cast 中的一种
static_cast
只要不包含底层 const,都可以使用,当需要把一个较大的算术运算类型赋值给较小的类型时,static_cast 非常有用,对于编译器无法自动执行的类型转换也十分有用,比如:将 void转换成 double
const_cast
只能改变运算对象的底层 const
reinterpret_cast
为运算对象的位模式提供较低层次上的重新解释
旧式强制类型转换
两种形式:
type(expr);
(type)expr;