# Глава 5.4. Перечисления Перечисления (enumerations) облегчают работу с данными, которые принимают фиксированное и заранее известное множество значений. ## Перечисления enum {#block-enum} [Перечисление](https://en.cppreference.com/w/c/language/enum) `enum` — это тип, значения которого ограничены набором именованных констант. Во многих код-стайлах имена констант задаются заглавными буквами: ```cpp {.example_for_playground .example_for_playground_004} // Создаем новый тип enum HashType { MD5, SHA1, SHA2 }; // Создаем объект этого типа HashType hash_type = SHA2; ``` Мы завели тип `HashType`. Переменные этого типа принимают одно из 3-х значений: `MD5`, `SHA1`, `SHA2`. Под капотом каждая из этих констант равна какому-то целому числу. За счёт этого компилятор может выполнить неявное преобразование: привести значение типа `HashType` к целочисленному типу. ```cpp {.example_for_playground .example_for_playground_005} // Оба варианта обращения к константам корректны: int k = HashType::MD5; int m = SHA1; HashType hash_type = SHA2; int n = hash_type; std::println("{} {} {}", k, m, n); ``` ``` 0 1 2 ``` Взгляните ещё раз на то, как выглядит создание перечисления. Создадим новый тип `Compression`, переменные которого могут принимать два значения — `QuickLZ` и `LZ4`: ```cpp {.example_for_playground .example_for_playground_006} enum Compression { QuickLZ, LZ4, }; ``` После объявления перечисления ставится оператор `;`. Такой синтаксис — очередное наследие Си, используемое и для классов со структурами. Он был введён, чтобы сразу после определения типа создавать его объект. Так выглядит одновременное создание нового типа `Compression` и переменной этого типа `compression_method`: ```cpp {.example_for_playground .example_for_playground_007} enum Compression { QuickLZ, LZ4, } compression_method; // ... compression_method = LZ4; ``` В современном C++ коде такая практика практически не встречается. Значение константы внутри перечисления можно определить явно после оператора `=`. Если этого не сделано, константа равна значению предыдущей, увеличенному на 1. Первая константа по умолчанию равна нулю. {#block-enum-const-values} Каковы целочисленные значения, принимаемые перечислением `State`? Укажите их через пробел. {.task_text} ```cpp enum State { Initialized, Paused, Done = 6, Reset }; ``` ```consoleoutput {.task_source #cpp_chapter_0054_task_0040} ``` `Initialized` — первая константа, значит, она равна нулю. Значение следующей константы равно значению предыдущей, увеличенному на 1. Значит, `Paused` равна 1. `Done` равна 6. И поэтому `Reset` равна 7. {.task_hint} ```cpp {.task_answer} 0 1 6 7 ``` ## Перечисления enum class Как вы только что узнали, у перечислений `enum` есть две особенности: - Имя константы доступно и без указания имени перечисления. Вместо `State::Reset` допустимо написать просто `Reset`. Это может привести к конфликту имён, если существует другая константа с таким же именем. - Значения перечислений неявно преобразуются к целочисленным типам и другим перечислениям. Такое поведение порождает массу ошибок. Чтобы их избежать, в C++11 был введён `enum class`. Он ничем не отличается от обычного `enum` кроме запрета неявных преобразований и безопасной работы с именами констант. [Старайтесь всегда использовать](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#renum-class) `enum class` вместо `enum`. ```cpp {.example_for_playground .example_for_playground_008} enum class ByteOrder { Native = 1, LittleEndian = 2, BigEndian = 3 }; ByteOrder bo1 = Native; // Ошибка ByteOrder bo2 = ByteOrder::Native; // ОК int n = ByteOrder::Native; // Ошибка ``` Заведите `enum class` `Rarity` со значениями `Common`, `Rare`, `Legendary`. {.task_text} Напишите функцию `to_string()`, которая принимает значение типа `Rarity` и возвращает соответствующую ему строку: `"Common"`, `"Rare"`, `"Legendary"`. {.task_text} В теле функции используйте `switch-case`. {.task_text} ```cpp {.task_source #cpp_chapter_0054_task_0050} // Перечисление Rarity // Функция to_string() ``` После объявления `enum class` не забудьте точку с запятой. Объявление `Rarity` должно идти до объявления функции `to_string()`. Все возвращаемые функцией строки начинаются с заглавной буквы. {.task_hint} ```cpp {.task_answer} enum class Rarity { Common, Rare, Legendary }; std::string to_string(Rarity rarity) { switch(rarity) { case Rarity::Common: return "Common"; case Rarity::Rare: return "Rare"; case Rarity::Legendary: return "Legendary"; } } ``` ---------- ## Резюме - Перечисление — это тип, значения которого ограничены набором именованных констант. - У перечисления `enum` имя константы доступно и без указания имени перечисления. А её значение неявно преобразуются к целочисленным типам и другим перечислениям. - Этих недостатков лишены перечисления `enum class`. Поэтому рекомендуется использовать их вместо `enum`.
Отправка...
Наша группа в telegram. Здесь можно задавать вопросы и общаться.
Задонатить. Если вам нравится курс, вы можете поддержать развитие площадки!