表达式

表达式

算数操作符

求模(只用于 整型[含 intboolcharshortlong] 数据)和除法运算在只有一个操作数为负数的时候,结果是取决于机器的。例如:

1
2
21 % -5; //结果取决于机器,可能为 1 或 -4 
21 / -5; //结果取决于机器,可能为 -4 或 -5

首先在符号上,求模运算的符号是取决于机器的,而除法运算的符号一定是负数

其次是结果上,数学表达式 21 ➗ -5 本身的结果是 -4.2。如果除出来的值向 0 一侧取整,也就是-4,如果除出来的结果向负无穷一侧取整,就是 -5。如果除法为 -4 的话,求模运算的结果就是 1,如果除法结果是 -5 的话,求模运算结果是 -4。

C++11规定结果为负数的除法一律向0取整(直接切除小数部分),同时也做出了一些新的规定:(-m) / n 和 m / (-n) 都等于 -(m / n) ; m % (-n) 等于 m % n ; (-m) % n 等于 -(m % n)

位操作符

对于位操作符~(位求反)<<(左移)>>(右移)&(位与)^(位异或)|(位或),由于不确定系统将如何处理符号位,所以应当将涉及到位运算的变量全部声明为 unsigned 类型。

移位操作(<<、>>)的右操作数不能是负数,而且必须是严格小于左操作数位数的值,否则操作的效果未定义。

内置赋值运算符

内置赋值运算符会把它左侧的对象当成左值返回

复合赋值操作符 op=

使用 op= 操作符时,左操作数只计算了一次,而是用相似的 a = a op b 时,左操作数会被计算两次

1
2
a += b;
a = a + b;

自增和自减操作符

注:只在必要时才使用后置操作符 a++。因为前置操作符 ++a 要做的工作比后置要少,前置可以直接返回+1后的结果,而后置需要保存操作数原来的值以便返回未+1的值作为结果

箭头操作符

方便指向类类型对象的指针访问其成员,以下两个等价

1
2
(*p).foo;
p->foo;

条件操作符 condition ? expr1 : expr2

这个三目运算符的落脚点在冒号的地方,两个expr 才是最终返回的值。所以一定不能把赋值语句写在 expr 里面。

1
2
3
4
int max = i < j ? i : j; //可行

int max_error = 0;
i < j ? max = i : max = j; //error

sizeof 操作符

对指针做 sizeof 操作将返回存放指针所需的内存大小(指针不需要有效);注意:如果要获取该指针所指向对象的大小,必须对其进行解引用操作!

C++11新标准允许使用作用域运算符来获取类成员的大小,不用通过具体的对象。

对数组做 sizeof 操作等效于对其数据类型做 sizeof 操作的结果乘上数组元素的个数。所以根据这个也能求出数组元素的个数

对 string 和 vector 对象执行 sizeof 运算只返回该类型固定部分的大小,不会计算对象中的元素占用了多少空间

1
int size = sizeof(ia) / sizeof(*ia); //由于数组的类型都是一样的,所以对数组名解引用代表了其所指向的对象,用sizeof求得大小理所应当

const 对象的动态分配和回收

通过 new 操作返回的地址上存放的是 const 对象,因此该地址只能赋值给指向 const 的指针,删除该对象和其他非 const 并无二致,如下

1
2
3
4
const int *pci = new const int(1024);

delete pci;
pci = 0;

算术转换

对于包含 signedunsigned int 的表达式,signed 类型会被转换成 unsigned 类型。如果 signed 类型是个负数的话,转换结果就是对 unsigned 类型取值数目求模之后的值。

显式转换

也称“强制类型转换”。有四种操作:static_castdynamic_castconst_castreinterpret_cast。虽然有时候需要这种转换,但是其本质都是危险的。不要乱用

命名的强制类型转换符号一般形式为

1
cast-name<type> (expression);

const_cast :将 const 对象转换为相应的非 const 对象。只有使用该转换才能将 const 性质转换掉,别的转换无法转换掉 const 性质,而 const_cast 也无法做别的。

static_cast :编译器执行的任何隐式转换都可以由 static_cast 显式完成。主要用于将一个较大的算术类型转换成一个较小的类型,他告诉读者和编译器:我们知道并且不关心潜在的精度损失,所以这样做可以消除“从大数据类型(如 double )转换到小数据类型(如 char)”时编译器产生的警告。这种转换还可以找回放在 void * 中的值,如

1
2
void *p = &d;
double *dp = static_cast<double *>(p);

reinterpret_cast :将操作数的内容解释为另一种不同的类型。这类强转本质上依赖于机器,而且是非常危险的。如

1
2
int *ip;
char *pc = reinterpret_cast<char *>(ip);

就得始终记得pc所指向的真实对象是 int 型而非字符数组。而且这个和旧式强制类型转换是一样的。