条件语句简介
到目前为止,我们创建的程序每次都以相同的方式工作。我们的程序无法做出决策。现在是时候改变这种状况了。在本课中,我们将根据用户输入的内容,为程序提供分支路径。这将是一个指导性课程,我们将制作一个应用程序,检查用户是否可以合法地获得驾驶执照。😎
代码准备
我们首先询问用户的出生年份。
#include <iostream>
int main()
{
std::cout << "Welcome to the Driver's License Oracle 2000\n";
std::cout << "Please enter your year of birth: ";
int year_of_birth;
std::cin >> year_of_birth;
// Year 2022 at the moment of writing this lesson
int age = 2022 - year_of_birth;
// Case A:
std::cout << "You can legally get a driver's license\n";
// Case B:
std::cout << "You cannot legally get a driver's license\n";
}
在这里,我强调了两段代码——一段是用户可以合法获得驾驶执照的情况,另一段是他们不能合法获得驾驶执照的情况。我们只想执行其中一个片段,而不是两个都执行。我们怎么能做到这一点呢?首先,我们应该明确“情况”是什么,以及在什么条件下它们应该执行。
- 情况 A — 合法 — 仅当
age
大于或等于18
时执行 - 情况 B — 非法 — 仅当
age
小于18
时执行
继续阅读,您将看到我们如何将这些情况转化为代码。
条件语句
C++ 中最简单的条件形式是 if
语句,其基本形式如下
if (/* boolean condition */)
{
// The code in here executes only if the condition evaluates to true
}
// The code out here executes regardless of whether the condition is true or false
要使用 if
语句,我们需要两样东西
- 一个在评估后产生布尔值
true
/false
的条件 - 当条件评估为
true
时执行的代码
在 if
关键字之后,我们将布尔条件放在括号内。然后,围绕 #2 的大括号创建了一个代码块。此代码块中的所有内容都将且仅在条件为真时执行。在代码块中创建的变量与该代码块共存亡——当代码块结束时(以右大括号 }
结束),它们就会被销毁,并且从代码块外部完全无法访问。
让我们将此应用于我们的驾驶执照示例,将 if 语句与我们之前确定的情况相结合
#include <iostream>
int main()
{
std::cout << "Welcome to the Driver's License Oracle 2000\n";
std::cout << "Please enter your year of birth: ";
int year_of_birth;
std::cin >> year_of_birth;
// Year 2022 at the moment of writing this lesson
int age = 2022 - year_of_birth;
// Case A:
if (/* age is greater than or equal to 18*/)
{
std::cout << "You can legally get a driver's license\n";
}
// Case B:
if (/* age is less than 18 */)
{
std::cout << "You cannot legally get a driver's license\n";
}
}
请注意,这里我们有两个 if
语句,每个情况一个。第一个处理我们的情况 A,即他们可以合法获得驾驶执照的情况。第二个处理我们的情况 B,即他们不能合法获得驾驶执照的情况。
仔细检查后,一个事实应该很快变得显而易见——这些情况是互斥的。这意味着两种情况不可能同时为真;只能执行其中一种。C++ 提供了 else
关键字来界定互斥条件。虽然上面的代码会按预期工作,但我们可以这样改进它
if (/* boolean condition */)
{
// The code in here executes only if the condition evalutes to true
}
else
{
// The code in here executes only if the condition evalutes to false
}
// The code out here executes regardless of whether the condition is true or false
这个 else
块是可选的,只有当你需要互斥时才应该使用它。
现在我们可以回到我们的示例,看到只需要一个条件,因为如果一个为真,则另一个必定为假。
#include <iostream>
int main()
{
std::cout << "Welcome to the Driver's License Oracle 2000\n";
std::cout << "Please enter your year of birth: ";
int year_of_birth;
std::cin >> year_of_birth;
// Year 2022 at the moment of writing this lesson
int age = 2022 - year_of_birth;
if (/* age is greater than or equal to 18*/)
{
std::cout << "You can legally get a driver's license\n";
}
else
{
std::cout << "You cannot legally get a driver's license\n";
}
}
;
不要在 if
语句的括号后面加分号 (;
)。这不会导致编译器错误,但会**导致**您的代码行为不正确。条件代码块将始终执行。
- ✔ 正确
- ❌ 错误
if (age >= 18)
// ...
else
// ...
if (age >= 18);
// ...
else;
// ...
总结一下,我们已经学习了如何将代码中条件执行的情况分离到专用的 if 语句中。这使我们能够根据程序中的各种值选择要运行的代码。现在我们已经有了 if-else 语句的基本结构,我们可以看看如何通过创建布尔条件来完成我们的程序。
布尔表达式
在 if
语句的括号内是布尔表达式,即一个求值为 true
或 false
的表达式。C++ 提供了几个新的运算符,允许我们形成这样的表达式。
布尔运算符
下面是一个表格,显示了 C++ 中可用的一些布尔运算符。布尔运算符是根据其输入返回布尔值 true
/false
的运算符。它们就像您在之前课程中看到的其他数学运算符一样,但它们不是求值为像 int
这样的数字,而是求值为 bool
(true
/false
)。
C++ 运算符 | 数学等价 | 描述 |
---|---|---|
a == b | a = b | a 等于 b 吗? |
a != b | a ≠ b | a 不等于 b 吗? |
a > b | a > b | a 严格大于 b 吗? |
a >= b | a ≥ b | a 大于或等于 b 吗? |
a < b | a < b | a 严格小于 b 吗? |
a <= b | a ≤ b | a 小于或等于 b 吗? |
相等运算符
我们表格的前两行 ==
和 !=
构成了相等运算符。这两个运算符允许我们检查两个值是否相同。相等运算符适用于大多数 C++ 类型,包括数字、字符串、布尔值等等。
单个 =
与双个 ==
不同。单个 =
是赋值运算符,例如当您创建或更改变量时。双个 ==
是相等运算符,当您想检查两个变量是否具有相同的值时使用。
因此,在 if
语句的条件中,当您想检查相等性时
- ✔
if (a == b)
- ❌
if (a = b)
关系运算符
我们表格的接下来四行构成了关系运算符。这两个运算符允许我们对两个值进行位置比较(例如在数轴上或按字母顺序)。关系运算符适用于某些 C++ 类型,例如数字和字符串;但是,我们尚未涵盖的许多其他类型不能这样比较。
我们现在掌握的知识足以让程序的第一版正常运行。提醒一下,我们需要创建一个条件,检查用户的年龄是否大于或等于 18。使用上表,最接近的匹配是 age >= 18
。现在我们可以填充我们的 if
语句
#include <iostream>
int main()
{
std::cout << "Welcome to the Driver's License Oracle 2000\n";
std::cout << "Please enter your year of birth: ";
int year_of_birth;
std::cin >> year_of_birth;
// Year 2022 at the moment of writing this lesson
int age = 2022 - year_of_birth;
if (age >= 18)
{
std::cout << "You can legally get a driver's license\n";
}
else
{
std::cout << "You cannot legally get a driver's license\n";
}
}
作为一项额外挑战,尝试使用其他剩余的关系运算符为 age >= 18
形成其他三种等效的表达方式。
复合布尔表达式
您可以通过所谓的逻辑运算符来转换和组合布尔表达式。它们是上面最初介绍的布尔运算符的一个子集,但它们旨在将布尔值作为输入。
C++ 支持这两种等效形式的运算符,即文本版本和符号版本。虽然符号表示在实际中更常见,但您可能会发现文本表示更容易理解和记住。您可以使用您最喜欢的一种,但请尽量保持一致!
C++ 运算符 | 替代表示 | 描述 |
---|---|---|
a and b | a && b | a 和 b 都为真吗? |
a or b | a || b | a 或 b 中任一为真吗? |
not c | !c | c 为假吗? |
逻辑 AND 运算符
逻辑 AND 运算符 and
/&&
接受两个布尔输入,并且当且仅当它的两个输入都为 true
时才返回 true
。当您想检查多个条件是否都为真,或者多个条件是否为 false
(通过同时使用否定运算符)时,最好使用它。
例如,false && true
为 false
,而 true and true
为 true
。
逻辑 OR 运算符
与 AND 类似,逻辑 OR 运算符 or
/||
接受两个布尔输入,并且当其中一个或两个输入都为 true
时返回 true
。当您想检查多个条件中的任何一个是否为真,或者一个变量是否是多种可能性中的一个时,最好使用它。
例如,false or false
为 false
,而 false || true
为 true
逻辑 NOT 运算符
请密切注意上表中的最后一行;not
/!
也称为逻辑非运算符。此运算符将翻转单个布尔输入的真值。因此,在表达式 !c
中,c
是一个布尔值(true
/false
),而 !
非运算符将 true→false
和 false→true
。这相当于询问 c
是否为 false
。此运算符在您想检查某个条件是否不成立时很有用。
例如,!(a == b)
等价于 a != b
。同样,not (a <= b)
等价于 a > b
。请注意这里如何使用括号来首先评估内部表达式,然后再对其进行逻辑否定。
升级神谕
州通过了新的法规,现在我们必须升级我们的 Oracle 程序以遵守。新法律规定了驾驶执照的最高年龄——65 岁及以上的人不再允许驾驶机动车辆。
我们需要扩展我们的布尔条件以遵守这项新要求。目前,age >= 18
设置了可接受值范围的下限。我们缺少设置上限的东西,它应该是 65。检查年龄是否小于 65 的布尔表达式可以写成 age < 65
。请注意,我们使用 <
而不是 <=
,因为 65 岁的人被禁止驾驶。
现在我们有 age >= 18
和 age < 65
,它们必须以某种方式组合。我们需要某种方式指定两者都必须为真——该人必须年满 18 岁或以上且小于 65 岁才能获得驾驶执照。
回顾复合布尔表达式中的表格,我们可以看到 and
/&&
运算符最适合这种情况。我们可以这样写这个复合条件:age >= 18 and age < 65
。请注意,这里的左右顺序无关紧要,这意味着 age < 65 and age >= 18
是一个等效条件。
#include <iostream>
int main()
{
std::cout << "Welcome to the Driver's License Oracle 3000\n";
std::cout << "Please enter your year of birth: ";
int year_of_birth;
std::cin >> year_of_birth;
// Year 2022 at the moment of writing this lesson
int age = 2022 - year_of_birth;
if (age >= 18 and age < 65)
{
std::cout << "You can legally get a driver's license\n";
}
else
{
std::cout << "You cannot legally get a driver's license\n";
}
}
您可能想将上述复合条件改写为 18 <= age < 65
。然而,这将不起作用。虽然它会编译,但会导致不正确的行为,因为它总是会评估为 true
。
使用相等运算符也会出现同样的不正确行为。例如,age1 == age2 == 18
或 age1 != age2 != 35
都将与上述示例类似,要么始终返回 false,要么始终返回 true。
切勿尝试链式使用相等或关系运算符。始终使用逻辑运算符 and
/&&
或 or
/||
来组合布尔表达式。有关其原因的更多信息,请参阅布尔值 » int↔bool 转换。
运算顺序
与数学运算符一样,布尔运算符也有其严格遵守的优先级顺序。类似于“PEMDAS”,括号内的内容总是首先被评估,其他运算符则根据下面列出的优先级进行计算。优先级最高在最上面。
运算符 | 名称 | 结合性 |
---|---|---|
! not | 逻辑非 | 右到左 🡠 |
* / % | 乘法/除法 | 左到右 🡢 |
+ - | 加法/减法 | 左到右 🡢 |
< <= > >= | 关系运算符 | 左到右 🡢 |
== != | 相等运算符 | 左到右 🡢 |
&& and | 逻辑与 | 左到右 🡢 |
|| or | 逻辑或 | 左到右 🡢 |
让我们用它来分析一些例子。
a > 10 and a < 100 or a == 150
// equivalent to
(a > 10 and a < 100) or a == 150
a * 4 == b + 5
// equivalent to
(a * 4) == (b + 5)
not a or b < 3701
// equivalent to
(not a) or (b < 3701)
not a != false
// equivalent to
(not a) != false
最好不要过分依赖运算符优先级的隐式规则。程序员可能很难记住所有关于哪个运算符优先评估的规则,因此编写太多依赖于这些规则的代码可能会使代码更难阅读和理解。如果您打算首先评估子表达式,最好将其放在括号中。
因此,与其写 a and b and c or a and not b
,不如考虑写 (a and b and c) or (a and not b)
。