4.3 逻辑和关系运算符(1)
关系运算符作用于算术类型或指针类型,逻辑运算符作用于任意能转换成布尔值的类型。逻辑运算符和关系运算符的返回值都是布尔类型。值为0的运算对象(算术类型或指针类型)表示假,否则表示真。对于这两类运算符来说,运算对象和求值结果都是右值。
|
表4.2:逻辑运算符和关系运算符
|
|
结合律
|
运算符
|
功能
|
用法
|
|
右
|
!
|
逻辑非
|
!expr
|
|
左
|
<
|
小于
|
expr < expr
|
|
左
|
<=
|
小于等于
|
expr <= expr
|
|
左
|
>
|
大于
|
expr > expr
|
|
左
|
>=
|
大于等于
|
expr >= expr
|
|
左
|
==
|
相等
|
expr == expr
|
|
左
|
!=
|
不相等
|
expr != expr
|
|
左
|
&&
|
逻辑与
|
expr && expr
|
|
左
|
||
|
逻辑或
|
expr || expr
|
逻辑与和逻辑或运算符
对于逻辑与运算符(&&)来说,当且仅当两个运算对象都为真时结果为真;对于逻辑或运算符(||)来说,只要两个运算对象中的一个为真结果就为真。
逻辑与运算符和逻辑或运算符都是先求左侧运算对象的值再求右侧运算对象的值,当且仅当左侧运算对象无法确定表达式的结果时才会计算右侧运算对象的值。这种策略称为短路求值(short-circuit eva luation)。
对于逻辑与运算符来说,当且仅当左侧运算对象为真时才对右侧运算对象求值。
对于逻辑或运算符来说,当且仅当左侧运算对象为假时才对右侧运算对象求值。
第3章中的几个程序用到了逻辑与运算符,它们的左侧运算对象是为了确保右侧运算对象求值过程的正确性和安全性。例如94页的循环条件:
- index != s.size() && !isspace(s[index])
首先检查index是否到达string对象的末尾,以此确保只有当index在合理范围之内时才会计算右侧运算对象的值。
举一个使用逻辑或运算符的例子,假定有一个存储着若干string对象的vector对象,要求输出string对象的内容并且在遇到空字符串或者以句号结束的字符串时进行换行。使用基于范围的for循环(参见3.2.3节,第91页)处理string对象中的每个元素:
- // s是对常量的引用;元素既没有被拷贝也不会被改变
- for (const auto &s : text) { // 对于text的每个元素
- cout << s; // 输出当前元素
- // 遇到空字符串或者以句号结束的字符串进行换行
- if (s.empty() || s[s.size() - 1] == ’.’)
- cout << endl;
- else
- cout << " "; // 否则用空格隔开
- }
输出当前元素后检查是否需要换行。if语句的条件部分首先检查s是否是一个空string,如果是,则不论右侧运算对象的值如何都应该换行。只有当string对象非空时才需要求第二个运算对象的值,也就是检查string对象是否是以句号结束的。在这条表达式中,利用逻辑或运算符的短路求值策略确保只有当s非空时才会用下标运算符去访问它。
值得注意的是,s被声明成了对常量的引用(参见2.5.2节,第69页)。因为text的元素是string对象,可能非常大,所以将s声明成引用类型可以避免对元素的拷贝;又因为不需要对string对象做写操作,所以s被声明成对常量的引用。
逻辑非运算符
逻辑非运算符(!)将运算对象的值取反后返回,之前我们曾经在3.2.2节(第87页)使用过这个运算符。下面再举一个例子,假设vec是一个整数类型的vector对象,可以使用逻辑非运算符将empty函数的返回值取反从而检查vec是否含有元素:
- // 输出vec的首元素(如果有的话)
- if (!vec.empty())
- cout << vec[0];
子表达式
- !vec.empty()
当empty函数返回假时结果为真。
关系运算符
顾名思义,关系运算符比较运算对象的大小关系并返回布尔值。关系运算符都满足左结合律。
因为关系运算符的求值结果是布尔值,所以将几个关系运算符连写在一起会产生意想不到的结果:
- // 哎哟!这个条件居然拿i < j的布尔值结果和k比较!
- if (i < j < k) // 若k大于1则为真!
if语句的条件部分首先把i、j和第一个<运算符组合在一起,其返回的布尔值再作为第二个<运算符的左侧运算对象。也就是说,k比较的对象是第一次比较得到的那个或真或假的结果!要想实现我们的目的,其实应该使用下面的表达式:
- // 正确:当i小于j并且j小于k时条件为真
- if (i < j && j < k) { /* . . . */ }