Table of Contents generated with DocToc
操作符执行什么操作以及操作结果的类型取决于操作数的类型。
一元操作符优先级最高,其次是乘除,接着是二元的加减。
求模操作符%
的操作数只能为整型,包括bool
,char
,short
,int
和long
以及对应的unsigned
。
两个操作数都是负数,除法结果为正,求模操作为负。如果只有一个操作数为负,这两种操作的结果取决于机器;求模结果的符号取决于机器,除法结果为负或零。
逻辑表达式存在短路求值。
不应该串接使用关系操作符 a > b > c
。
如果操作数为负数,则位操作符如何处理其符号位依赖于机器。
移位操作的右操作数不可以是负数,且必须是小于左操作数的值,否则操作的效果未定义。
IO操作为左结合。
赋值操作符是右结合的,返回左值。
使用复合赋值+=
时,左操作数只计算一次,而使用相似的长表达式时,左操作数计算两次。
*iter++
等效于 *(iter++)
箭头操作符相当于引用和指针操作符加上括号。
(*p).foo
等价于 p->foo
;
cond ? expr1 : expr2
cond
肯定要计算,后两个只有一个表达式被计算。
避免条件操作符的深度嵌套。
在输出表达式中使用条件表达式,通常要用括号。
cout << (i < j ? i : j); //ok: prints larger of i and j
cout << (i <j) ? i : j; //print 1 or 0,相当于 cout << (i <j) ; cout ? i : j
cout << i < j ? i : j ; //error:compares cout to int
sizeof
返回一个对象或类型名的长度,类型为size_t
,sizeof
的结果是编译时常量。
sizeof
作用于expr
时,并没有计算表达式的值。
对数组做sizeof
等效于对其元素类型做sizeof
的结果乘以数组元素的个数,数组不会退化为指针!
从左至右,其结果最右边表达式。
优先级和结合性决定了表达式的哪部分用作哪个操作符的操作数。
++
的优先级高于*
。
除了&&
、||
、条件和逗号操作符,C++并未指定其操作数的求值顺序。
处理复合表达式的原则:
1、尽量用括号。
2、要修改操作数的值,则不要再同一个语句的其他地方使用该操作数。也可以分成两个独立于语句。
如果不提供显式初始化,动态创建的对象与函数内定义的变量初始化方式相同:对于类类型的对象,用该类的默认构造函数,内置类型的对象无初始化。
int *pi = new int; //pi points to an uninitialized int
int *pi = new int(); //pi points an int value-initialized to 0
new
失败会抛出bad_alloc
的异常。
如果指针指向的不是new
分配的内存地址,那么delete
就是不合法的。
零值指针,如果指针为0,则在其上做delete
是合法的。
delete
之后,该指针变成垂悬指针,很难检测。
允许创建动态的const
对象。
以下三种常见的错误与动态内存分配有关:
- 删除指向动态分配内存的指针失败:内存泄漏。
- 读写已删除的对象。
- 对同一内存空间两次
delete
。
如果表达式的操作数分别为整数和浮点型,则整数转换为浮点型。
发生隐式转换的情况:
1、 混合类型的表达式中,其操作数转换为相同的类型。
2、 用作条件表达式转换为bool
。
3、 用同一表达式初始化或赋值某个变量。
整数提升:所有比int
小的整型,如果该类型的所有可能的值都能包容在int
中,就被提升为int
,否则就是被提升为unsigned int
。
包含signed
和unsigned int
的表达式,signed
会被转换为unsigned
。
使用数组时,大多数情况下,数组都会自动转换为指向第一个元素的指针。
指向任何数据类型的指针都可以转换为void*
,整形数值常量0可转换为任意指针类型。
将枚举类型提升为什么类型,由机器定义,并依赖于枚举成员的最大值。
显式转换 cast-name<type>(expression)
dynamic_cast
支持运行时识别指针或引用指向的对象。const_cast
转换掉表达式的const性质。static_cast
隐式执行的任何类型转换都可以用它完成。reinterpret_cast
为操作数的位模式提供较低层次的重新解释。
旧式强制类型转换依赖于所涉及的数据类型,具有和const_cast
,static_cast
, reinterpret_cast
一样的行为。
上一章:4. 数组和指针
下一章:[6. 语句](6. 语句.md)