Урок №59. Классы enum

  Юрий  | 

    | 

  Обновл. 21 Апр 2019  | 

 17345

 ǀ   8 

Хоть перечисления и считаются отдельными типами данных в C++, они не столь безопасны, как кажутся на первый взгляд, и, в некоторых случаях, позволят вам делать вещи, которые не имеют смысла. Например:

Когда C++ будет сравнивать переменные fruit и color, он неявно преобразует их в целочисленные значения и сравнит эти целые числа. Так как значениями этих двух переменных являются перечислители, которым присвоено значение 0, то это означает, что в примере выше fruit = color. А это не совсем то, что должно быть, так как fruit и color из разных перечислений и их вообще нельзя сравнивать (фрукт и цвет!). С обычными перечислителями нет способа предотвратить подобные сравнения.

Для решения этой проблемы в C++11 добавили классы enum (или ещё «перечисления с областью видимости»), которые добавляет перечислениям, как вы уже могли понять, локальную область видимости со всеми её правилами. Для создания такого класса нужно просто добавить ключевое слово class сразу после enum. Например:

Стандартные перечислители находятся в той же области видимости, что и само перечисление (в глобальной области видимости), поэтому вы можете напрямую получить к ним доступ (например, PINK). Однако, с добавлением класса, который ограничивает область видимости каждого перечислителя к области видимости его перечисления, для доступа к нему потребуется оператор разрешения области видимости (например, Colors::PINK). Это значительно снижает риск возникновения конфликтов имён.

Поскольку перечислители являются частью класса enum, то необходимость добавлять префиксы к идентификаторам отпадает (например, можно использовать просто PINK вместо COLOR_PINK, так как Colors::COLOR_PINK уже будет лишним).

А строгие правила типов классов enum означают, что каждый класс enum считается уникальным типом. Это означает, что компилятор не сможет сравнивать перечислители из разных перечислений. Если вы попытаетесь это сделать, компилятор выдаст ошибку (как в примере выше).

Однако учтите, что вы можете сравнивать перечислители внутри одного класса enum (так как эти перечислители являются одного типа):

С классами enum компилятор больше не сможет неявно конвертировать значения перечислителей в целые числа. Это хорошо! Но иногда могут быть ситуации, когда нужно будет вернуть эту особенность. В таких случаях вы можете явно преобразовать перечислитель класса enum в тип int, используя оператор static_cast:

Если вы используете компилятор, поддерживающий C++11, то нет никакого смысла использовать обычные перечисления вместо классов enum.

Обратите внимание, ключевое слово class вместе с ключевым словом static являются одними из самых запутанных в языке C++, поскольку имеют разные значения в зависимости от контекста. Хотя классы enum используют ключевое слово class, в C++ они не считаются традиционными «классами». О традиционных классах мы поговорим несколько позже.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (128 оценок, среднее: 4,87 из 5)
Загрузка...

Комментариев: 8

  1. Аватар Алексей:

    Интересно. Первый пример запилил в vim и пробовал скомпилить — warning: comparison between ‘enum main()::Fruits’ and ‘enum main()::Colors’ [-Wenum-compare]

  2. Аватар WiseWanderer:

    Забыли написать, что можно тип указывать:

  3. Аватар Владимир:

    Возвращаясь к уроку 46, можно вместо такой записи

    Использовать такую:

    Как плюсы, используется 4 байта для всех флагов (сюда можно затолкать и 32 флага) вместо 8 байтов + повышение читабельности кода. Единственное, что нехорошо — постоянно придётся делать явное преобразование типов:

    Но если убрать ключевое слово class, то можно работать с флагами без преобразования.

    1. Аватар Константин:

      Владимир, а скажи мне: в чём разница между

      и

      ?

      Если это ОЧЕпятка, то как у тебя этот код вообще работал? Если это просто теория, то набросай какую задачу можно целиком (не фрагмент) этими флагами решить. Спасиб.

      1. Аватар Владимир:

        Как я указал в комменте, разница в том, что emun выделит 4 байта для хранения этих флагов, в то время как каждое использование const unsigned char будет создавать переменную размером в 1 байт. Если создать 32 флага, то через const unsigned char это всё займет 32 байта, в то время, как через enum — все те же 4. Так же повышает и читабельность кода, т.к. флаги группируются в одно перечисление, к тому же получают своё имя, по которому сгруппированы. Ещё раз повторюсь, читать коммент надо было внимательнее, я там всё это указал.
        Код прекрасно работает, если не знаком с битовыми масками, то тебе в 46-ой урок, читай, вникай. Там и задача как раз есть, её и реши, только вместо этого:

        Используй это:

        1. Аватар Алексей:

          Идея, наверное, неплохая… Вот только вопрос в производительности этого кода (и читабельности тоже)… Мне что-то внутри подсказывает что в больших проектах постоянное использование static_cast будет неплохо тормозить работу проекта… Ну а без class не очень безопасно… Впрочем, если я не прав, то поправьте

  4. Аватар Алибек:

    Что-то я не вижу преимуществ enum перед enum class

    1. Юрий Юрий:

      Классы enum добавили позднее и это уже усовершенствованные enum. Если ваш компилятор поддерживает C++11, то смысла использовать enum в рабочих проектах, вместо классов enum — нет.

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *