我们将首先讨论控制流语句中的第一类——条件语句。条件语句用于指定在何种情况下应执行与之关联的一条或多条语句。
C++ 支持两种基本的条件语句:if 语句(《if 语句简介》中介绍,本节将继续展开)和 switch 语句(将在后续两节讲解)。
if 语句快速回顾
C++ 中最基本的条件语句是 if 语句,其语法形式如下:
if (condition)
    true_statement;
或带可选的 else 分支:
if (condition)
    true_statement;
else
    false_statement;
若条件求值为真,则执行 true_statement;若条件求值为假且存在 else 分支,则执行 false_statement。
以下示例程序展示了带 else 的 if 语句:
#include <iostream>
int main()
{
    std::cout << "Enter a number: ";
    int x{};
    std::cin >> x;
    if (x > 10)
        std::cout << x << " is greater than 10\n";
    else
        std::cout << x << " is not greater than 10\n";
    return 0;
}
程序运行结果符合预期:
Enter a number: 15
15 is greater than 10
Enter a number: 4
4 is not greater than 10
if 或 else 后需多条语句时
初学者常写出如下代码:
#include <iostream>
namespace constants
{
    constexpr int minRideHeightCM { 140 };
}
int main()
{
    std::cout << "Enter your height (in cm): ";
    int x{};
    std::cin >> x;
    if (x >= constants::minRideHeightCM)
        std::cout << "You are tall enough to ride.\n";
    else
        std::cout << "You are not tall enough to ride.\n";
        std::cout << "Too bad!\n"; // 关注此行
    return 0;
}
然而,程序的一次运行结果如下:
Enter your height (in cm): 180
You are tall enough to ride.
Too bad!
结果不符合预期,原因在于 true_statement 与 false_statement 均只能为单条语句。缩进在此处产生误导——上述代码实际等价于:
#include <iostream>
namespace constants
{
    constexpr int minRideHeightCM { 140 };
}
int main()
{
    std::cout << "Enter your height (in cm): ";
    int x{};
    std::cin >> x;
    if (x >= constants::minRideHeightCM)
        std::cout << "You are tall enough to ride.\n";
    else
        std::cout << "You are not tall enough to ride.\n";
    std::cout << "Too bad!\n"; // 始终执行
    return 0;
}
由此可见,“Too bad!” 总会被执行。
若需根据条件执行多条语句,应使用复合语句(即语句块):
#include <iostream>
namespace constants
{
    constexpr int minRideHeightCM { 140 };
}
int main()
{
    std::cout << "Enter your height (in cm): ";
    int x{};
    std::cin >> x;
    if (x >= constants::minRideHeightCM)
        std::cout << "You are tall enough to ride.\n";
    else
    { // 添加语句块
        std::cout << "You are not tall enough to ride.\n";
        std::cout << "Too bad!\n";
    }
    return 0;
}
由于语句块被视为单条语句,程序现可正确运行:
Enter your height (in cm): 180
You are tall enough to ride.
Enter your height (in cm): 130
You are not tall enough to ride.
Too bad!
隐式语句块
若程序员未在 if 或 else 后的语句部分显式声明语句块,编译器将隐式创建。因此:
if (condition)
    true_statement;
else
    false_statement;
实际等价于:
if (condition)
{
    true_statement;
}
else
{
    false_statement;
}
多数情况下,此差异无关紧要。然而,初学者有时会试图在隐式块中定义变量,例如:
#include <iostream>
int main()
{
    if (true)
        int x{ 5 };
    else
        int x{ 6 };
    std::cout << x << '\n';
    return 0;
}
该程序无法通过编译,编译器报错标识符 x 未定义。原因在于上述代码等价于:
#include <iostream>
int main()
{
    if (true)
    {
        int x{ 5 };
    } // x 在此处销毁
    else
    {
        int x{ 6 };
    } // x 在此处销毁
    std::cout << x << '\n'; // x 已离开作用域
    return 0;
}
在此情形下,x 具有语句块作用域,并在块结束时被销毁;到达 std::cout 语句时,x 已不存在。
if 或 else 后单条语句是否加块的取舍
程序员社区对单条语句是否显式加块存在争议。
支持始终加块的理由:
- 不加块易在无意中添加看似受条件控制、实则不受的语句。例如: - if (age >= minDrinkingAge) purchaseBeer();- 匆忙中追加功能: - if (age >= minDrinkingAge) purchaseBeer(); gamble(); // 始终执行- 结果未成年人也能赌博,后果严重! 
- 不加块可能增加调试难度: - if (age >= minDrinkingAge) addBeerToCart(); // 条件执行 checkout(); // 始终执行- 若怀疑 - addBeerToCart()出错而将其注释:- if (age >= minDrinkingAge) // addBeerToCart(); checkout(); // 意外变为条件执行- 若始终加块,上述问题均可避免。 
- C++23 引入的 - if constexpr要求必须使用块,因此加块可保持- if与- if constexpr的一致性。
反对加块的主要理由:
- 加块会垂直拉长代码,减少一屏可见行数,降低可读性,可能引发更严重错误。
社区观点更倾向于始终加块,尽管该建议尚未成为普遍共识。
最佳实践
初学者宜将与 if 或 else 关联的单条语句置于块内。经验丰富的开发者有时为获得更紧凑的垂直间距可不遵循此做法。
折中方案:将单行语句与 if 或 else 置于同一行:
if (age >= minDrinkingAge) purchaseBeer();
else std::cout << "No drinky for you\n";
该方法在牺牲少量可读性的同时避免了前述两个问题。
对单行写法的一个合理批评是调试困难:
- 条件与语句在同一执行步骤完成,难以判断语句是否实际执行。
- 二者位于同一行,无法在语句处单独设断点。
若调试时受上述限制,可在条件与语句间插入换行(分占两行),调试后再恢复。
if-else 与连续 if 的选择
初学者常困惑何时使用 if-else(if 后接若干 else)与连续 if(多个并列 if)。
- 若仅希望执行首个为真条件后的代码,应使用 if-else。
- 若希望执行所有为真条件后的代码,应使用连续 if。
示例如下:
#include <iostream>
void ifelse(bool a, bool b, bool c)
{
    if (a)      // 始终求值
        std::cout << "a";
    else if (b) // 仅当先前条件为假时求值
        std::cout << "b";
    else if (c) // 仅当先前条件为假时求值
        std::cout << "c";
    std::cout << '\n';
}
void ifif(bool a, bool b, bool c)
{
    if (a) // 始终求值
        std::cout << "a";
    if (b) // 始终求值
        std::cout << "b";
    if (c) // 始终求值
        std::cout << "c";
    std::cout << '\n';
}
int main()
{
    ifelse(false, true, true);
    ifif(false, true, true);
    return 0;
}
调用 ifelse(false, true, true) 时,a 为假,不执行对应语句,转而执行 else;b 为真,输出 b,后续 else 不再执行。仅首个为真条件后的代码被执行。
调用 ifif(false, true, true) 时,a 为假,跳过;b 为真,输出 b;c 为真,输出 c。所有为真条件后的代码均被执行。
再看下例:
char getFirstMatchingChar(bool a, bool b, bool c)
{
    if (a) // 始终求值
        return 'a';
    else if (b) // 仅当先前条件为假时求值
        return 'b';
    else if (c) // 仅当先前条件为假时求值
        return 'c';
    return 0;
}
由于使用 if-else,仅首个为真条件后的代码被执行。但当每条关联语句均返回值时,可改写为:
char getFirstMatchingChar(bool a, bool b, bool c)
{
    if (a) // 始终求值
        return 'a'; // 条件为真即返回
    if (b) // 仅当先前条件为假时求值
        return 'b'; // 条件为真即返回
    if (c) // 仅当先前条件为假时求值
        return 'c'; // 条件为真即返回
    return 0;
}
表面看似连续 if,然而一旦首个条件为真,函数即返回,后续 if 不再求值,因此行为与前述版本等价。当所有关联语句均返回值时,多数程序员倾向省略 else,以减少冗余并使条件对齐更佳。
核心洞见
若所有关联语句均返回值,可直接使用连续 if,此时 else 并无额外价值。
下一节将继续深入探讨 if 语句。
