运算符基本概念
1.对于含有多个运算符的复杂表达式来说,要想理解它的含义首先要理解运算级、结合律、以及运算对象的求值顺序。
2.重载运算符:当运算符作用于类类型的运算对象时,用户可以自定义其含义。在使用重载运算符时,其包括运算对象的类型和返回值的类型都是由该运算符定义的;但是运算对象的个数、运算符的优先级和结合律都是无法改变的。
3.C++中左值右值的含义不像C语言中那么简单,做一个归纳:当一个对象被用作右值的时候用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。有几个熟悉的运算符是要用到左值的:赋值运算符、取地址符、某些解引用运算符及递增递减运算符和下标运算符。
4.使用decltype关键字时左值和右值也有所不同。若表达式求值结果是一个左值,将得当引用类型。
5.对于那些没有指定执行顺序的运算符来说,如果表达式指向并修改了同一个对象,将会引发错误并产生未定义的行为。运算对象的求值顺序与优先级和结合律无关。有四种运算符明确规定了求值顺序:(&&)、(||)、(?:)、(,)。
6.处理复合表达式的两个经验:
①.拿不准时最好用括号让表达式组合关系符合程序逻辑要求。
②.如果改变了某个运算对象的值,在表达式的其他地方不要再使用这个运算对象。(重要例外:当改变运算对象的子表达式本身就是另一个子表达式的运算对象时除外)
运算符
1.算数运算符的运算对象和求值结果都是右值。在表达式求值之前,小整数类型的运算对象被提升成较大的整数类型,所有运算对象最终会转换成同一类型。
2.取余运算的运算对象必须是整数类型,且m%(-n)与m%n等价。
3.关系运算符作用于指针类型,逻辑运算符作用于任意能转换成布尔值的类型。
4.对逻辑与和逻辑或运算符来说,当且仅当左侧运算对象无法确定表达式的结果时才会计算右侧对象的值,这种策略称为短路求值。
5.赋值运算符的左侧对象必须是一个可修改的左值,赋值运算的结果是它的左侧运算对象并且是一个左值,且结果类型是左侧运算对象的类型。
6.因为赋值运算符的优先级低于关系运算符的优先级,所以在条件语句中赋值部分通常应该加上括号。
7.养成使用前置递增递减运算符的习惯,这样不仅不需要担心性能的问题,而且更重要的是写出的代码会更符合编程的初衷。
8.因为递增递减运算符会改变运算对象的值,所以要提防在复合表达式中错用这两个运算符。
9.当条件运算符的两个表达式都是左值或者能转换成同一种左值类型时运算结果为左值,否则运算的结果是右值。
10.条件运算符可以嵌套。
11.条件运算符的优先级非常低,因此当一条长表达式中嵌套了条件运算子表达式时通常要在它两端加上括号。
12.位运算符作用于整数类型的运算对象,并把运算对象看成二进制位的集合。
13.关于符号位如何处理没有明确规定,所以强烈建议仅将位运算符用于处理无符号类型。
14.对位运算符来说如果运算对象是小整型,则它的值会被提升。
15.灵活运用位运算符可以达到意想不到的效果,例如可以用char存储32个数据。
16.sizeof运算符有两种形式:sizeof (type) 和 sizeof expr。
17.sizeof并不实际计算其运算对象的值,在sizeof中解引用一个无效指针仍然是一种安全的行为,因为指针实际上并没有被真正使用。
18.对string和vector对象执行sizeof运算只返回该类型固定的大小,不会计算对象中的元素占用了多少空间。
类型转换
1.隐式转换:
①.算数转换,其中注意整数的提升和无符号类型的运算对象
②.数组转换成指针
③.指针转换,包括整数常量0或字面值nullptr转换成任意指针类型、指向任意非常量的指针转换成void*以及指向任意对象的指针能转换成const void*
④.转换成布尔类型
⑤.转换成常量
⑥.类类型定义的转换
2.显示转换(命名的强制):
①.dynamic_cast
②.static_cast:当需要把一个较大的算数类型赋给较小类型或对于编译器无法自动执行的类型转换非常有用,当将void*类型指针强制转换为原来类型时,必须确保转换后所得的类型就是指针所指的类型
③.const_cast:只能改变运算对象的底层const
④.reinterpret_cast:尽量不要使用
尽量避免使用强制类型转换