表达式求值顺序
-
有4种运算符明确规定了运算对象的求值顺序:
①逻辑与(&&)当且仅当左侧运算对象为真时才对右侧运算对象求值
②逻辑或(||)当且仅当左侧为假时才对右侧运算对象求值
③条件(?:)运算符
④逗号(,)运算符 -
其他运算符无求值顺序,且与优先级和结合律无关。
运算符
-
算术运算符
①算术运算符的运算对象和求值结果都是右值。
②运算顺序:一元正负(+、- ) —— 乘除余(*、/、%) —— 二元加减(+、-)。
③C++中取余运算不考虑溢出情况下,m%(-n)等于m%n,(-m)%n等于-(m%n)。 -
逻辑和关系运算符
①逻辑和关系运算符的运算对象和求值结果都是右值。
②运算顺序:(!) —— (<、<=、>、>=) —— (==、!=) —— (&&、||)。 -
赋值运算符
①运算符左侧运算对象是可修改的左值,返回左侧运算对象,求值结果是左值,满足右结合律。 -
递增递减运算符
①运算符作用于左值运算对象,前置版本将对象本身作为左值返回,后置版本将对象原始值的副本作为右值返回。 -
成员访问运算符
①点运算符和箭头运算符都可用于访问成员。
②箭头运算符作用于指针类型的运算对象,结果是左值。
③点运算符如果成员所属对象是左值则结果是左值,如果成员所属对象是右值则结果是右值。 -
条件运算符
①cond ? expr1 : expr2,如果两个表达式都是左值或者能转换成同一种左值类型,运算结果是左值,否则运算结果是右值。 -
位运算符
①运算顺序:(~) —— (<<、>>) —— (&) —— (^) —— (|)。 -
sizeof运算符
①sizeof(type),sizeof expr,第二种形式返回表达式结果类型的大小,不实际计算运算对象的值。
②sizeof * p,sizeof满足右结合律并且与*运算符优先级一样,等价于sizeof (*p)。
③sizeof解引用一个无效指针仍然是安全行为,指针实际没有真正使用,不需要真的解引用也能知道它所指对象的类型,不实际求运算对象的值,所以p是无效指针也没关系。
④C++11允许sizeof运算符作用于作用域运算符获取类成员大小。 -
逗号运算符
①含有两个运算对象,按照从左向右的顺序依次求值,对左侧表达式求值,丢掉求值结果,返回结果为右侧表达式的值,若右侧运算对象为左值,运算符结果为左值。
类型转换
-
隐式类型转换
①在大多数表达式中,比int类型小的整数值首先提升为较大的整数类型。
②在条件中,非布尔值转换成布尔类型。
③初始化过程,初始值转换成变量的类型,赋值语句,右侧运算对象转换成左侧运算对象的类型。
④算术运算或关系运算的运算对象有多种类型,需转换成同一种类型。
⑤函数调用时类型转换。
⑥数组转换成指针,指针转换成布尔类型,转换成常量,及类类型定义的转换。 -
显示转换
①cast-name<type>(expression),如果type是引用类型,则结果是左值,cast-name 是static_cast、dynamic_cast、const_cast、reinterpret_cast。
②任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast。
③const_cast只能改变运算对象的底层const,将常量对象转换成非常量对象,如果对象本身不是一个常量,使用强制类型转换获得写权限是合法行为,如果对象是一个常量,执行强制类型转换后获得的写操作会产生未定义的后果。
④reinterpret_cast通常为运算对象的位模式提供较低层次上的重新解释,只是重新解释未实际变换。
⑤dynamic_cast支持运行时类型识别,基类指针及派生类对象。
语句:
-
范围for语句
①for(declaration : expression),expression必须为序列(花括号的初始值列表、数组、vector或string等类型的对象)。
②序列的特点是有能返回迭代器的begin和end成员。
③declaration定义一个变量,序列中的每个元素能转换成该变量的类型,可使用auto类型说明符,如果需要对序列中的元素执行写操作,循环变量声明成引用类型。 -
break语句
①负责终止离它最近的while、do while、for或switch语句。 -
continue语句
①终止最近循环中当前迭代并立即开始下一次迭代,只能出现在while、do while、for循环内部。 -
goto语句
①从goto语句无条件跳转到同一函数内的另一条语句。