第四章 表达式
1.一元运算符:作用于一个运算对象的运算符,比如&、*等;
二元运算符:作用于两个运算对象的运算符,比如==,乘号;
还有三元运算符和函数调用。
2.C++定义了运算符作用于内置类型和复合类型的运算对象时所执行的操作,当运算符作用于类类型的运算对象时,用户可以自行定义其含义,因为这种自定义的过程事实上是为 已存在的运算符赋予了另外一层含义,称之为重载运算符。
3. 左值:左值表达式的求值结果是一个对象或者一个函数,然而然而以常量对象为代表的某些左值不能作为赋值语句的左侧运算对象;
右值:求值结果是一个值。
当一个对象被用作右值的时候,用的是对象的值,当对象被用作左值的时候,用的是对象的身份。
4.算术运算符
优先级:一元正号“+”、一元负号“-” > 乘 除 余 > 加 减
溢出:当计算结果超出该类型所能表示的范围时就会产生溢出。
取余取模运算符% ,负责计算两个整数相除所得的余数,参与取余运算的运算对象必须是整数类型。
特别的,如果m和 n是整数且n非0,则 (m/n)*n+m%n=m, m%(-n)=m%n (-m)%n=-(m%n)
5.逻辑与关系运算符
逻辑与关系运算符所返回的值都是布尔型。
优先级:逻辑非! > 小于 小于等于 大于 大于等于 > 等于== 、不等于!= >逻辑与 && > 逻辑或 ||
逻辑与和逻辑或运算符都是先求左侧运算对象的值再求右侧运算对象的值,当且仅当左侧运算对象无法确定表达式的结果时才会计算右侧对象的值,这种策略称之为短路求值。
对于逻辑与运算符来说,当且仅当左侧运算符为真时才对右侧运算对象求值;
对于逻辑或运算符来说,当且仅当左侧运算符为假时才对右侧运算对象求值。
if(i<j<k)不要这样使用,因为先求i<j 返回的是一个布尔值,这个布尔值再与k比较,这是不对的。所以应该使用if(i<j && j<k )
6.赋值运算符
赋值运算符满足右结合律,这一点与其他二元运算符不同。 a=b=0;
优先级:赋值运算符优先级较低,低于关系运算符,所以通常需要加上括号。
7.递增和递减运算符
有两种形式:前置版本和后置版本。 不建议使用后置。
前置:int i=0 ; j=++i ; // j=1; i=1 首先将运算对象i加1,然后将改变后的对象作为求值结果给j;
后置:int i=0 ; j=i++ ; // j=0; i=1 首先将运算对象i加1,但是求值结果是运算对象改变之前的那个值的副本。
后置递增运算符的优先级高于解引用运算符,所以*a++ 等价于 *(a++) ,解引用运算符的运算对象时a未增加之前的值。
通常不建议使用后置,所以cout<< *a++ ; 可以分开写为 cout<<*a ; ++a;
8.成员访问运算符
包括点运算符 和 箭头运算符
9.条件运算符
优先级:非常低,通常要加括号
条件运算符: (条件 ? 表达式1:表达式2),执行过程是如果条件为真,则对表达式1求值并返回该值,否则对表达式2求值并返回该值。
可以在表达式中使用嵌套运算符: ( 条件1 ? ( 条件2 ? 表达式1 : 表达式2) : 表达式3)
10.位运算符
位运算符作用于整数类型的运算对象,并把运算对象看成是二进制的集合,位运算符提供检查和设置二进制位的功能。
优先级: 位求反~ > 左移<< 、右移 >> > 位与 & > 位异或 ^ > 位或 | 关系运算符、赋值运算符、条件运算符 < 位运算符优先级 < 算术运算符
建议将位运算符用于处理无符号类型。
11.sizeof运算符
sizeof运算符返回一条表达式或一个类型名字所占的字节。 所得的值是一个size_t类型(无符号类型)。
运算符的运算对象有两种形式: sizeof(type) 和 sizeof expr 第二个中返回的是表达式结果类型的大小
对char或类型为char的表达式执行sizeof ,结果是1;
对指针执行sizeof得到指针本身所占空间大小,32位VS运行时为4个字节;
对数组执行sizeof得到整个数组所占空间大小。比如int a[ ]={1,2,3}; sizeof(a) 为12 因为每个Int 元素占4个字节,一共三个元素,所以为12.
对string 和vector 执行sizeof运算,返回该类型固定部分的大小。vector 返回16 string返回 28。 关于sizeof 和sizeof(string)
12.逗号运算符
(a,b) 首先对左侧的表达式求值,然后将求值结果丢弃,逗号运算符真正返回的结果是右侧表达式的值。
13. 类型转换
隐式转换:C++语言不会直接将两个不同的类型的值相加,而是先根据类型转化规则将运算对象的类型统一后再求值。这种类型转换是自动执行的。
算术转换:把一种算数类型转换为另一种算数类型。
当表达式中既有浮点又有整数类型时,整数值将转换为响应的浮点类型;运算符的运算对象总是转换为最宽的类型。
整数提升:负责把小整数类型转换成较大的整数类型。对于bool, char ,signed char ,unsigned char ,short ,unsigned short类型来说提升成int型。
较大的char类型(wchar_t ,char16_t ,char32_t)提升成int ,unsigned int ,long ,unsigned long ,long long ,unsigned long long 中最小的一种类型。
前提是转换后的类型要能容纳原类型的所有可能的值。
如果一个运算对象时无符号型,另一个对象是带符号类型,其中无符号类型不小于带符号类型,那么带符号类型转换成无符号类型。
显式转换:强制类型转换 cast_name<type>(expression) type是转换的目标类型,expr是要转换的值,cast_name有四种:
(1)static_cast 任何具有明确定义的类型转换,只要不包含底层const,都可以使用这个类型,当需要把较大的算数类型赋给较小类型时,这个类型很常用;
(2)const_cast 用于将常量对象转换成非常量对象的行为,称其为去掉const性质。
(3)reinterpret_cast 为运算对象的位模式提供较低层次上的重新解释。WTF??
(4)dynamic_cast 支持运行时类型识别。