章节目录

Switch语句基础

本节阅读量:

尽管可以将许多if-else语句链接在一起,但这既难以阅读,又效率低下。考虑以下程序:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

void printDigitName(int x)
{
    if (x == 1)
        std::cout << "One";
    else if (x == 2)
        std::cout << "Two";
    else if (x == 3)
        std::cout << "Three";
    else
        std::cout << "Unknown";
}

int main()
{
    printDigitName(2);
    std::cout << '\n';

    return 0;
}

根据传入的值,printDigitName() 中的变量x最多将求值三次,这是低效的。

根据一组不同的值测试变量或表达式很常见的,因此C++提供了另一种称为switch语句的条件语句,该语句专门用于此目的。下面是与上面相同的程序:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>

void printDigitName(int x)
{
    switch (x)
    {
        case 1:
            std::cout << "One";
            return;
        case 2:
            std::cout << "Two";
            return;
        case 3:
            std::cout << "Three";
            return;
        default:
            std::cout << "Unknown";
            return;
    }
}

int main()
{
    printDigitName(2);
    std::cout << '\n';

    return 0;
}

switch语句背后的思想很简单:计算表达式(有时称为条件)以产生值。如果表达式的值等于任何case标签之后的值,则执行匹配的case标签后面的语句。如果找不到匹配的值并且存在默认标签,则改为执行默认标签之后的语句。

与原始的if语句相比,switch语句的优点是只对表达式求值一次(使其更有效率),switch语句还使读者更清楚地看到,在每个情况下,都有哪些对应的处理语句。

让我们更详细地研究一下这些概念。


使用switch语句

我们通过使用switch关键字来启动switch语句,后跟括号,其中包含要在其中求值的条件表达式。表达式通常只是单个变量,但它可以是任何有效的表达式。

一个限制是,条件必须求值为整数类型(请参见基本数据类型的介绍)或枚举类型(在未来的–无范围枚举中介绍),或者可以转换为一个整数或枚举值。此处不能使用计算为浮点类型、字符串和大多数其他非整型的表达式。

在条件表达式之后,声明了一个代码块。在块内部,我们使用标签来定义要测试相等性的所有值。有两种标签。


case标签

第一种标签是case标签,它使用case关键字声明,后跟常量表达式。常量表达式必须与条件表达式的类型匹配,或者必须可转换为该类型。

如果条件表达式的值等于case标签后的表达式,则从该case标签之后的第一条语句开始执行,然后按顺序继续。

下面是示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>

void printDigitName(int x)
{
    switch (x) // x 为 2
    {
        case 1:
            std::cout << "One";
            return;
        case 2: // 与这个标签匹配
            std::cout << "Two"; // 从这里开始执行
            return; // 然后函数返回
        case 3:
            std::cout << "Three";
            return;
        default:
            std::cout << "Unknown";
            return;
    }
}

int main()
{
    printDigitName(2);
    std::cout << '\n';

    return 0;
}

此代码打印:

1
Two

在上面的程序中,计算x产生值2。由于存在值为2的case标签,因此执行将跳转到该匹配case标签下的语句。程序打印Two,然后执行return语句,函数返回给调用者。

对于可以具有的case标签的数量没有实际限制,但switch中的所有case标签都必须是唯一的。也就是说,您不能这样做:

1
2
3
4
5
6
switch (x)
{
    case 54:
    case 54:  // error: 54已经存在
    case '6': // error: '6' 会转换为整数 54, 也已经存在
}

如果条件表达式与任何case标签都不匹配,则不会执行任何case语句。


default标签

第二种标签是default标签(通常称为默认情况),它是使用default关键字声明的。如果条件表达式与任何case标签都不匹配,并且存在default标签,则从default标签之后的第一条语句开始执行。

下面是与default标签匹配的示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>

void printDigitName(int x)
{
    switch (x) // x 是 5
    {
        case 1:
            std::cout << "One";
            return;
        case 2:
            std::cout << "Two";
            return;
        case 3:
            std::cout << "Three";
            return;
        default: // 5与任何case标签都不匹配
            std::cout << "Unknown"; // 所以从这里开始执行
            return; // 然后返回给调用者
    }
}

int main()
{
    printDigitName(5);
    std::cout << '\n';

    return 0;
}

打印:

1
Unknown

default标签是可选的,每个switch语句只能有一个default标签。按照惯例,default情况放在switch块中的最后一个。


没有匹配的case标签,也没有default标签

如果条件表达式的值与任何case标签都不匹配,并且没有default标签,则不会执行switch内的任何语句。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>

void printDigitName(int x)
{
    switch (x) // x 是 5
    {
    case 1:
        std::cout << "One";
        return;
    case 2:
        std::cout << "Two";
        return;
    case 3:
        std::cout << "Three";
        return;
    // 没有匹配的case标签,也没有defaule标签
    }

    // 所以从这里继续执行
    std::cout << "Hello";
}

int main()
{
    printDigitName(5);
    std::cout << '\n';

    return 0;
}

在上面的示例中,x求值为5,但没有与5匹配的case标签,也没有default标签。因此,不会执行任何switch内的语句。从switch后继续执行,打印Hello。


使用break关键字

在上面的例子中,我们使用return语句来停止标签后面的语句的执行。然而,这也会退出整个函数。

break语句(使用break关键字声明)告诉编译器,我们已经完成了在switch中执行语句的操作,需要执行switch后的下一条语句。这允许我们在不退出整个函数的情况下退出switch语句。

下面是一个稍微修改的示例,使用break而不是return重写:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>

void printDigitName(int x)
{
    switch (x) // x 是 3
    {
        case 1:
            std::cout << "One";
            break;
        case 2:
            std::cout << "Two";
            break;
        case 3:
            std::cout << "Three"; // 从这里开始执行
            break; // 跳出switch代码块
        default:
            std::cout << "Unknown";
            break;
    }

    // 从这里继续执行
    std::cout << " Ah-Ah-Ah!";
}

int main()
{
    printDigitName(3);
    std::cout << '\n';

    return 0;
}

上面的示例打印:

1
Three Ah-Ah-Ah!

那么,如果不以break或return结束标签下的一组语句,会发生什么呢?在下一课中,我们将探索该主题。


8.3 Constexpr if语句

上一节

8.5 switch fallthrough机制与作用域

下一节