左值可以位于赋值语句的左侧,而右值不可以
当一个对象被用作右值当时候,用的是对象的值(内容);当对象被用作左值当时候,用的是对象的身份。
后面写的内容没看太明白
复合表达式:指含有两个或多个运算符的表达式。
高优先级运算符的运算对象要比低优先级运算符的对象更为紧密地结合在一起。如果优先级相同,则其组合规则由结合律确定。
括号无视优先级和结合律
优先级规定了运算对象的组合方式,但是没有说明运算对象按照什么顺序求值。
int i = f1()*f2(); //f1和f2的执行顺序无法知道
对于f() + g() * h() + j()
表达式中:
+、-、*、/、%
其中+\-
也可以作为一元运算符。一元运算符的优先级最高,解下来是乘法和除法,优先级最低的是加法和减法。优先级高的运算符比优先级低的运算符组合得更紧密。
对于+
,可以用于指针,但只会返回这个指针的一个副本,即现在有两个指针指向该地址了。
int a = -4; int *b = &a; int *c = +b; *c = 10; cout << a << endl; //10
进行比较运算时,除非比较对象是布尔类型,否则不要使用布尔字面值true/false作为运算对象
if(val == true) //如果val不是布尔类型会将true转换为1 //推荐使用 if(val) if(!val)
赋值运算的结果是它的左侧运算对象,并且是一个左值。相应的,结果的类型就是左侧运算对象的类型。如果赋值运算符的左右两个运算对象类型不同,则右侧运算对象将转换成左侧运算对象的类型。
int k = 0; int k = 3.1415;//结果是3
C++11新标准允许使用花括号括起来的初始值列表作为赋值语句的右侧运算对象
int k = {3.14}; //错误,窄化转换 (空间大的转空间小的) vector<int> vi = {0,1,2,3,4,5,6,7,8,9};
无论左侧运算对象的类型是什么,初始值列表都可以为空。此时,编译器创建一个值初始化的临时量(根据类型决定,int为0)并将其赋给左侧运算对象。
+= -= *= /= %= //算术运算符 <<= >>= &= |= ^= //位运算符
使用复合运算符好处:只求值一次!
这个与平常写代码的习惯可能不一样,一定需要注意!
即推荐++i
而不是i++
原因:后置版本需要将原始值存储下来以便返回这个未修改的内容。如果我们不需要修改前的内容,那么后置版本的操作就是一种浪费。
对于整数和指针类型来说,编译器可能对这种额外的工作进行了一定的优化;但是对于相对复杂的迭代器类型,这种额外的工作就消耗巨大。所以一定要养成使用前置版本的习惯
点运算符只能用于类类型的对象!成员所属的对象是左值,那么结果是左值,反之如果是右值,那么结果是右值。
箭头运算符作用于一个指针类型的运算对象,将解引用和成员访问两个操作结合在一起,即it->mem
和(*it).mem
左值就是能出现在等号左边的值,即能够通过地址(名字)访问的对象,右值即出现在等号右边的,即是创建的临时变量。
cond ? expr1 : expr2 finalgrade = (grade > 90) ? "high" : (grade < 60) ? "fail" : "pass";
条件运算符的优先级非常低,与别的混用的时候一定要加括号
条件运算符满足右结合律(从右往左结合,但是判定还是从左往右看),即有多个条件运算符嵌套时,优先计算右边的条件运算符结果,如图中的(grade < 60) ? "fail" : "pass"
的结果
值得注意的是:二进制位或者向左移或者向右移,移出边界之外的位就被舍弃掉了
cout << "hi" << "there" << endl; ((cout<<"hi") << "there") << endl;
cout << 42 + 10; //true cout << (10 < 42); //true cout << 10 < 42; //false 因为相当于比较cout和42的大小
sizeof (type) sizeof expr
sizeof有两种用法,返回的是size_t类型的值。
因为sizeof满足右结合律并且与*
运算符的优先级一样,所以表达式按照从右向左的顺序组合。
sizeof *p == sizeof(*p) //指针p指向类型的内容大小(注意是类型) sizeof p //指针p的所占空间大小
这里也可以看出,sizeof指向的对象不一定是具体的对象,只需要知道类型即可,因为获取大小与具体对象是什么并无关系。
一个比较普遍的转换方式是,短类型转成宽类型。