12.17 – Вложенные типы в классах

Добавлено 10 июля 2021 в 18:11

Рассмотрим следующую короткую программу:

#include <iostream>
 
enum FruitType
{
    APPLE,
    BANANA,
    CHERRY
};
 
class Fruit
{
private:
    FruitType m_type;
    int m_percentageEaten = 0;
 
public:
 
 
    Fruit(FruitType type) :
        m_type(type)
    {
    }
 
    FruitType getType() { return m_type;  }
    int getPercentageEaten() { return m_percentageEaten;  }
};
 
int main()
{
    Fruit apple(APPLE);
    
    if (apple.getType() == APPLE)
        std::cout << "I am an apple";
    else
        std::cout << "I am not an apple";
    
    return 0;
}

В этой программе нет ничего плохого. Но поскольку перечисление FruitType предназначено для использования вместе с классом Fruit, немного странно иметь его независимо от самого класса.

Вложенные типы

В отличие от функций, которые не могут быть вложены друг в друга, в C++ типы могут быть определены (вложены) внутри класса. Для этого вы просто определяете тип внутри класса под соответствующим спецификатором доступа.

Вот та же программа, что и выше, с определением FruitType внутри класса:

#include <iostream>
 
class Fruit
{
public:
    // Обратите внимание: мы переместили FruitType
    // внутрь класса под спецификатор открытого доступа
    enum FruitType
    {
        APPLE,
        BANANA,
        CHERRY
    };
 
private:
    FruitType m_type;
    int m_percentageEaten = 0;
 
public:
 
 
    Fruit(FruitType type) :
        m_type(type)
    {
    }
 
    FruitType getType() { return m_type;  }
    int getPercentageEaten() { return m_percentageEaten;  }
};
 
int main()
{
    // Обратите внимание: теперь мы получаем доступ к FruitType через Fruit
    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 теперь определен внутри класса. Во-вторых, обратите внимание, что мы определили его под спецификатором открытого доступа, поэтому к определению типа можно получить доступ извне класса.

Классы, по сути, для любых вложенных типов действуют как пространства имен. В предыдущем примере мы могли получить доступ к перечислителю APPLE напрямую, потому что перечислитель APPLE был помещен в глобальную область видимости (мы могли бы предотвратить это, используя класс перечисления вместо перечисления, и в этом случае мы получали бы доступ к APPLE через FruitType::APPLE). Теперь, поскольку FruitType считается частью класса, мы получаем доступ к перечислителю APPLE, добавляя к нему префикс с именем класса: Fruit::APPLE.

Обратите внимание: поскольку классы перечисления также действуют как пространства имен, если бы мы вложили FruitType внутрь Fruit как класс перечисления вместо перечисления, мы получали бы доступ к перечислителю APPLE через Fruit::FruitType::APPLE.

Другие типы также могут быть вложенными

Хотя перечисления, вероятно, являются наиболее распространенным типом, вкладываемым внутрь классов, C++ позволяет вам определять внутри класса и другие типы, такие как определения типов typedef, псевдонимы типов и даже другие классы!

Как и любой обычный член класса, вложенные классы имеют такой же доступ к членам включающего их класса, что и сам включающий их класс. Однако вложенный класс не имеет специального доступа к указателю this включающего его класса.

Еще одно ограничение вложенных типов – их нельзя объявлять предварительно. Это ограничение может быть снято в будущей версии C++.

Определение вложенных классов не очень распространено, но стандартная библиотека C++ делает это в некоторых случаях, например, с классами итераторов. Мы рассматривали итераторы в уроке «10.24 – Знакомство с итераторами».

Теги

C++ / Cppenum / ПеречислениеLearnCppДля начинающихКласс (программирование)ОбучениеПрограммированиеТипы данных

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.