Skip to content

13.17 - 类中的嵌套类型

考虑下面这个简短的程序:

 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
32
33
34
35
36
#include <iostream>

enum class FruitType
{
    apple,
    banana,
    cherry
};

class Fruit
{
private:
    FruitType m_type {};
    int m_percentageEaten { 0 };

public:
    Fruit(FruitType type) :
        m_type { type }
    {
    }

    FruitType getType() const { return m_type; }
    int getPercentageEaten() const { return m_percentageEaten; }
};

int main()
{
    Fruit apple { FruitType::apple };

    if (apple.getType() == FruitType::apple)
        std::cout << "I am an apple";
    else
        std::cout << "I am not an apple";

    return 0;
}

这个程序并没有任何问题。但是因为限定作用域枚举(枚举类) FruitType 只会在 Fruit 类中使用,所以将它定义在类外作为一个独立的枚举类多少有些不妥。

嵌套类型

数据和函数可以称为类的成员,在C++中,类型也可以被嵌套地定义在类内。为此,你只需要将类型定义在内合适的成员访问修饰符下方即可。

下面的程序类似于之前的例子,只不过枚举被定义在了类内(此处使用了无作用域枚举类型)。

 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
32
33
34
35
36
37
38
39
40
#include <iostream>

class Fruit
{
public:
    // 注意:FruitType 被移动到了类中,位于pubic部分
    // 同时我们将枚举类变成了枚举
    enum FruitType
    {
        apple,
        banana,
        cherry
    };

private:
    FruitType m_type {};
    int m_percentageEaten { 0 };

public:
    Fruit(FruitType type) :
        m_type { type }
    {
    }

    FruitType getType() const { return m_type; }
    int getPercentageEaten() const { return m_percentageEaten; }
};

int main()
{
    // 注意,我们此处是通过 Fruit 来访问 FruitType
    Fruit apple { Fruit::apple };

    if (apple.getType() == Fruit::apple)
        std::cout << "I am an apple";
    else
        std::cout << "I am not an apple";

    return 0;
}

首先,FruitType 的定义现在位于类内。其次,我们将其定义为public,以便能够从类的外部访问它。

此时的类名实际上充当着所有嵌套类型的命名空间,和么枚举类有些类似。在之前的例子中,因为我们使用了枚举类,所以在使用枚举时必须添加 FruitType:: 作用域限定符。在这个例子中,因为FruitType 是一个普通的枚举,但是它作为该类的一部分,在访问时也必须添加 FruitType:: 作用域限定符。

注意,因为枚举类也可以充当命名空间,所以如果在上面的例子中使用枚举类而不是枚举,则在访问时必须添加 Fruit::FruitType:: 作用域限定符。这实在是没有以,所以我们选择使用普通枚举。

其他可嵌套类型

虽然枚举可能是最常被嵌套在类中的类型,但C++允许你在类中定义其他类型,例如类型定义、类型别名,甚至其他类!

与类的任何普通成员一样,嵌套类对外围类的成员具有与外围类相同的访问权限。然而,嵌套类对外围类的“this”指针没有任何特殊的访问权限。

嵌套类型的另一个限制是它们不能被前向声明。然而,在实践中这很少会带来问题,因为整个类定义(包括嵌套类型)通常可以在需要的地方使用被“#include”。

定义嵌套类并不常见,但C++标准库在某些情况下确实会这样做,比如迭代器类。