本期主题:常用运算符
我们在C++菜鸟学习笔记系列(12)中讨论了关于表达式中的一些基本概念,下面我们来接着学习关于运算符的一些内容。
(1)算术运算符
我们对于算术运算符的优先级可以简单了解为:
乘法(*) > 除法(/) > 取余(%) > 加法(+) > 减法(-)
对于上述的算术运算符都比较简单,我们只需要注意它们都满足左结合律就可以了。除此之外我们还需要关注的是取余运算符(%)中参与运算的运算对象必须是整数类型。而其他运算符在没有特殊说明的情况下可以作用于任意算术类型(C++可以自动转换成一种类型,或者我们在运算之前进行转换)。
例如:
int i = 3, j = 7, r;
double k = 3.14;
r = j % i;
cout << "r = " << r << endl;
r = j % k; // error
cout << "r = " << r << endl;
(2)逻辑和关系运算符
逻辑运算和关系运算符的返回值都是布尔类型,值为0的运算对象(可以为算术类型或是指针类型)表示假,否则表示真。
那么什么是逻辑运算符,什么是关系运算符呢?
(2.1)逻辑运算符:
! // 逻辑非 ! i
&& //逻辑与 i && j
|| //逻辑或 i || j
对于逻辑与(&&)运算符来说,当且仅当两个运算对象都为真的时候结果为真,对于逻辑或(||)运算符来说,只要其中一个运算对象为真,结果就为真。
逻辑与和逻辑或运算符都是先求左侧运算对象的值再求右侧运算对象的值,当左侧运算对象的值无法确定整个表达式的结果时才会计算右侧运算对象的值。
例如:
if(f1() && f2())
当且仅当f1()的值为真,我们才需要知道f2()的具体值,而当f1()的值为假时,我们能判断这个表达式的结果一定为假,不需要知道f2()的具体值。
类似的,逻辑对于或运算符,当且仅当左侧运算对象的值为假时我们才需要知道右侧对象的具体值。(这种策略被称为“短路求值”)
(2.2)关系运算符:
< // 小于
< = // 小于等于
>// 大于
> = // 大于等于
! = //不等于
= = // 等于
顾名思义,关系运算符就是比较运算对象的大小关系并返回结果的布尔值。关系运算符也满足左结合律,同时我们要注意,因为关系运算符的求值结果是布尔值,所以我们不能把几个关系运算符连续写在一起。
例如:
if ( i < j < k)
这一行代码中我们按照左结合律可以写成if ( (i < j) < k)这样就是i和j比较大小结果的布尔值再和k的值进行比较,这是不能够得到我们所期望的运算的。
而实际上我们常用:
if ( i < j && j < k)
来实现我们期待中的运算。
(3)赋值运算符:
赋值运算符(=)对于我们来说十分常见,我们在前面的博客()中也曾经介绍了关于赋值和初始化的一些区别。我们这里就简单介绍一下关于赋值运算符使用过程中的一些注意要点。
1.赋值运算的左侧运算对象必须是一个可以修改的左值(且不包括const常量)
2.赋值运算满足又结合律(这一点和前面介绍的运算符不同),例如:
int i = j = k =0;
是合法的(0赋给k,k赋给j,j再赋值给i)。
3.赋值运算符的优先级较低(和其他运算符一起使用时最好把其组合的对象用小括号括起来)
4.不要把关系运算符中的相等( == )和赋值运算符混淆。
(4)递增和递减运算符:
递增(++)和递减(–)运算符为对象的加1和减1操作提供了一种简洁的书写形式。(迭代器中位置的移动也常常用到这两个运算符)
递增和递减运算符有两种形式:前置和后置。我们可以简单的理解为递增和递减运算符前置则在当前表达式中运算对象的值就已经发生改变,而后置版本中的运算对象在当前表达式中的值仍然是改变前的值,在下一条语句中才会改变。
注意:我们在C++语言中更常用递增和递减运算符前置的形式,因为后置会把运算对象的原始值存储下来,以便返回这个未修改的内容,这在很多时候对于我们来说是一种浪费。
(5)成员访问运算符:
访问运算符有点运算符(.)和箭头运算符(->)。其中点运算符是获取类对象中的一个成员。箭头运算符也与其类似。
表达式:
student -> num;
等价于表达式:
(*student).num;
这里我们要注意点运算符(.)的优先级高于解引用运算符(*),所以我们一定要在解引用运算符处加上括号,否则就会出现错误。(我们总不能渴望去访问指针的成员吧)
(6)条件运算符:
条件运算符(?:)类似于我们常用的 if-else语句,其使用形式常常如下所示:
条件判断 ? (true)结果1 : (false) 结果2
例如:
string final = (grade < 60) ? "fail" : " pass";
这条语句中我们先判断成绩(grade)是否小于60分,如果小于60则字符串final为"fail",相反如果判断为假字符串final为" pass"。
对于这条语句我们还可以改写成:
if (grade < 60)
final = "fail";
else
final = " pass";
条件运算符满足右结合律,也是是说运算对象一般从右向左的顺序组合,对于这一点我们在嵌套条件运算符中可能要考虑到,但是嵌套条件运算符的可读性很差,我们一般不要超过两到三层。下面我们看一个小例子:
string final =(grade > 90) ? "excellent" : (grade < 60) ? "fail" : " pass";
可以看出我们把成绩分为了3等(“excellent”,“fail” , " pass"),从右往左看,我们先判断成绩是否小于60,如果小于60则右面这一子表达式的结果为"fail"反之为" pass",然后再继续执行左侧的条件表达式,如果大于90则为"excellent",反之则为右侧条件表达式的结果。
(7)位运算符:
尽管我们很多时候都没有用到过位运算符,但是我们还是有必要了解到其优先级和结合律以及它的相关含义的。
位运算符一般作用于整数类型运算处理,并把运算对象看成是二进制位的集合。后面我们也会介绍到一种bitset标准库类型可以表示任意大小的二进制位集合,也可以应用位运算符。
位运算符也满足左结合律,常见的位运算符如下所示:
~ //位求反
<< //左移,在右侧插入值为0的二进制位
>> //右移,在左侧插入值为0的二进制位
& //位与,如果两个运算对象相应位置都是1则运算结果对象中的相应位置也是1
^ //位异或,当且仅当两个运算对象相应位置不同时,值为1,也可以记为只有一个1时为1
| //位或,当有一个1时就是1
对于位移运算符我们要注意:C++对于符号位如何处理没有明确的规定,所以我们最好将位运算符应用于处理无符号类型;我们还要注意不要把位运算符和逻辑运算符混淆在一起。
关于位移运算符我们这里不做过多介绍了,大家可以再自行了解。
好了,这次就先写到这里了。
注:虽然这篇博客的内容十分简单,但是大家若有转载还请标明出处!