Объявление перечисления в классе

В следующем фрагменте кода перечисление Color объявлено в классе Car, чтобы ограничить область действия перечисления и попытаться не «загрязнять» глобальное пространство имен.

class Car
{
public:

   enum Color
   {
      RED,
      BLUE,
      WHITE
   };

   void SetColor( Car::Color color )
   {
      _color = color;
   }

   Car::Color GetColor() const
   {
      return _color;
   }

private:

   Car::Color _color;

};

(1) Это хороший способ ограничить область применения перечисления Color? Или я должен объявить его вне класса Car, но, возможно, в его собственном пространстве имен или структуре? Я только что натолкнулся на эту статью сегодня, которая защищает последнюю и обсуждает некоторые приятные моменты о enums: http://gamesfromwithin.com/stupid-c-tricks-2-better-enums .

(2) В этом примере при работе внутри класса лучше всего кодировать перечисление как Car::Color, или достаточно Color? (Я полагаю, что первое лучше, на случай, если в глобальном пространстве имен будет объявлен еще один перечисление Color. Таким образом, по крайней мере, мы явно говорим о перечислении, на которое мы ссылаемся.)

140
задан ROMANIA_engineer 6 October 2017 в 17:52
поделиться

4 ответа

  1. Если Цвет специфичен только для Car s, то таким образом вы ограничите его область действия. Если вы собираетесь иметь другое перечисление Color , которое используют другие классы, то вы также можете сделать его глобальным (или, по крайней мере, вне Car ).

  2. Это не имеет значения. Если есть глобальный, то локальный все равно будет использоваться, так как он ближе к текущей области. Обратите внимание, что если вы определяете эту функцию вне определения класса, вам необходимо явно указать Car :: Color в интерфейсе функции.

81
ответ дан 23 November 2019 в 23:15
поделиться

Я предпочитаю следующий подход (код ниже). Он решает проблему "загрязнения пространства имен", но также является гораздо более безопасным для типов (вы не можете назначать и даже сравнивать два разных перечисления или ваше перечисление с любые другие встроенные типы и т. д.).

struct Color
{
    enum Type
    {
        Red, Green, Black
    };
    Type t_;
    Color(Type t) : t_(t) {}
    operator Type () const {return t_;}
private:
   //prevent automatic conversion for any other built-in types such as bool, int, etc
   template<typename T>
    operator T () const;
};

Использование:

Color c = Color::Red;
switch(c)
{
   case Color::Red:
     //некоторый код
   break;
}
Color2 c2 = Color2::Green;
c2 = c; //error
c2 = 3; //error
if (c2 == Color::Red ) {} //error
If (c2) {} error

Я создаю макрос для облегчения использования:

#define DEFINE_SIMPLE_ENUM(EnumName, seq) \
struct EnumName {\
   enum type \
   { \
      BOOST_PP_SEQ_FOR_EACH_I(DEFINE_SIMPLE_ENUM_VAL, EnumName, seq)\
   }; \
   type v; \
   EnumName(type v) : v(v) {} \
   operator type() const {return v;} \
private: \
    template<typename T> \
    operator T () const;};\

#define DEFINE_SIMPLE_ENUM_VAL(r, data, i, record) \
    BOOST_PP_TUPLE_ELEM(2, 0, record) = BOOST_PP_TUPLE_ELEM(2, 1, record),

Использование:

DEFINE_SIMPLE_ENUM(Color,
             ((Red, 1))
             ((Green, 3))
             )

Некоторые ссылки:

  1. Herb Sutter, Jum Hyslop, C / C ++ Users Journal, 22 (5), май 2004 г.
  2. Херб Саттер, Дэвид Э. Миллер, строго типизированные перечисления Бьярна Страуструпа (версия 3), июль 2007 г.
65
ответ дан 23 November 2019 в 23:15
поделиться

Если вы создаете библиотеку кода, я бы использовал пространство имен. Однако внутри этого пространства имен по-прежнему может быть только одно перечисление Color. Если вам нужно перечисление, которое может использовать общее имя, но может иметь разные константы для разных классов, используйте свой подход.

3
ответ дан 23 November 2019 в 23:15
поделиться

В общем, я всегда помещаю свои перечисления в структура . Я видел несколько рекомендаций, включая «префикс».

enum Color
{
  Clr_Red,
  Clr_Yellow,
  Clr_Blue,
};

Всегда думал, что это больше похоже на рекомендации C , чем на C ++ (во-первых, из-за аббревиатуры, а также из-за пространств имен в C ++ ).

Итак, чтобы ограничить область видимости, у нас теперь есть две альтернативы:

  • пространства имен
  • структуры / классы

Я лично предпочитаю использовать структуру , потому что ее можно использовать в качестве параметров для программирования шаблонов. в то время как пространство имен не может быть изменено.

Примеры манипуляций:

template <class T>
size_t number() { /**/ }

, который возвращает количество элементов перечисления внутри структуры T :)

7
ответ дан 23 November 2019 в 23:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: