表达式由一个或者多个运算对象组成的,对表达式求职将得到一个结果,字面值和变量是最简单的表达式,其结果就是字面值和变量的值。
表达式的基础
- c++定义了一元运算符和二元运算符。
- 重载运算符:当运算符作用在类类型的运算对象时,用户可以自行定义其含义。(运算对象的个数、运算符的优先级和结合律都是无法改变的)
- 左值右值:
- 左值可以在表达式左边,右值不能。
- 当一个对象被用作右值的时候,用的是对象的值(内容)
- 当对象用做左值时,用的是对象的身份(在内存中的位置)
- 当一个左值被当作右值使用时,实际使用的是它的内容(值)
求值顺序、优先级、结合律
- 运算对象的求值顺序与优先级和集合律无关。
算术运算符
- 溢出:当计算的结果超出该类型所能表示的范围时就会产生溢出。
+ - | 一元正负号 | + expr-expr |
---|---|---|
* | 乘法 | expr*expr |
/ | 除法 | expr/expr |
% | 求余 | expr%expr |
+ | 加法 | expr+expr |
- | 减法 | expr-expr |
int i=1024;
int k=-i;//k=-1024
bool b=true;
bool b2=-b;//b2是true
- 对于大多数运算符来说,布尔型的运算对象将被提升为int类型。布尔变量b的值为真,参与运算时将被提升成整数值为1,对它求负变成-1,将-1再转换成布尔值,不是0,所以为真。
逻辑运算符
- 短路求值:逻辑与运算符和逻辑或运算符都是先求左侧运算对象的值再求右侧运算对象的值,当且仅当左侧运算对象无法确定表达式的结果时才会计算右侧运算对象的值。
- 进行比较运算时除非比较的对象时布尔类型,否则不要使用运算求值的顺序。
赋值运算符
- 如果赋值运算的左右侧运算对象类型不同,则右侧运算对象将转换成左侧运算对象的类型。
- 赋值运算符满足右结合律,这点和其他二元运算符不一样。 ival = jval = 0;等价于ival = (jval = 0);
- 赋值运算优先级比较低。
递增递减运算符
- 除非必须,否则不使用递增递减运算符的后置版本
int i=0;j;
j=++i;//j=1,i=1
j=i++;//j=1,i=2
成员访问符
- ptr->men
- (*ptr).men
条件运算符
- 条件运算符(?:)允许我们把简单的if-else逻辑嵌入到单个表达式中去,按照如下形式:cond? expr1: expr2
- 随着条件运算嵌套层数的增加,代码的可读性急剧下降,因此,条件运算的嵌套不要超过两到三层。
位运算符
- 位运算符是作用于整数类型的运算对象。
- 二进制位向左移(<<)或者向右移(>>),移出边界外的位就被舍弃掉了。
- 位取反(~)、与(&)、或(|)、异或(^)
sizeof运算符
- 返回一条表达式或一个类型名字所占的字节数。返回的类型是 size_t。
- 两种形式: sizeof (type)和 sizeof expr
隐式类型转换
- 比 int类型小的整数值先提升为较大的整数类型。
- 条件中,非布尔转换成布尔。
- 初始化中,初始值转换成变量的类型。
- 算术运算或者关系运算的运算对象有多种类型,要转换成同一种类型。
- 函数调用时。
无符号类型的运算对象
- 如果一个运算对象是无符号类型、另一个运算对象是带符号类型,而且其中的无符号类型不小于带符号类型,那么带符号的运算对象转换成无符号的。
- 带符号类型大于无符号类型,此时转换的结果依赖于机器。如果无符号类型的所有值都能存在该带符号类型中,则无符号的运算转换成带符号类型。如果不能,那么带符号类型的运算转换成无符号类型。
显式类型转换(尽量避免)
- static_cast:任何明确定义的类型转换,只要不包含底层const,都可以使用。 double slope = static_cast(j);
- dynamic_cast:支持运行时类型识别。
- const_cast:只能改变运算对象的底层const,一般可用于去除const性质。 const char *pc; char p = const_cast<char>(pc)
- reinterpret_cast:通常为运算对象的位模式提供低层次上的重新解释。