Enum (перечисления)
Это тип данных, где любое значение (перечислитель) определяется как символьная константа.
enum Colors
{
// ниже перечислители - все возможные значения этого типа данных
COLOR_RED, // автоматом присваивается 0
COLOR_BROWN, // 1
COLOR_GRAY, // 2
COLOR_WHITE, // 3
COLOR_PINK, // 4
COLOR_ORANGE,// 5
COLOR_BLUE, // 6
COLOR_PURPLE,// 7
// последняя запятая разрешена начиная с С++11
};
Colors background_color = COLOR_RED;
Colors font_color = COLOR_PINK;
std::cout << font_color; // 4
Преимущество такого подхода в том, что объявление перечислений не требует выделения памяти. Память выделяется тогда, когда переменная перечисляемого типа определена.
Стоит обратить внимание на то, что разные enum не могут содержать перечислители с одинаковыми именами (поскольку перечислители вместе с enum находяться в одном пространстве имён):
enum Colors
{
YELLOW,
BLACK,
PINK
};
enum Feelings
{
SAD,
ANGRY,
BLACK // error
};
А потому нередко можно встретить названия перечислителей с названием enum в качестве префикса: COLORS_BLACK
.
Так же перечислителям можно самому определять значения (при этом не определенные будут иметь значение больше на единицу чем прошлый):
enum Animals
{
ANIMAL_PIG = -4,
ANIMAL_LION, // автоматически присваивается -3
ANIMAL_CAT, // -2
ANIMAL_HORSE = 6,
ANIMAL_ZEBRA = 6, // значения могут повторяться
ANIMAL_COW // 7
};
Компилятор не будет неявно конвертировать целочисленное значение в значение перечислителя:
Colors color = 7; // error
Однако это можно сделать при помощи static_cast:
Colors color = static_cast<Colors>(7); // лучше так не делать
Однако у стандратного enum есть свои минусы:
enum Colors
{
COLORS_RED,
COLORS_GREEN,
COLORS_BLUE
};
enum Cars
{
CARS_RED,
CARS_GREEN,
CARS_BLUE
};
int main()
{
// создают перечислители в глобальной области видимости (из-за чего нельзя давать перечислителям разных enum одинаковые имена + загрязнение global scope):
// можно преобразовать в int:
int x = COLORS_RED;
int y = CARS_RED;
// более того компилятор их и так неявно преобразует в __int__ при сравнении:
if (x == y) std::cout << "true\n"; // 0 == 0
if (x == CARS_RED) std::cout << "true\n";
if (y == COLORS_RED) std::cout << "true\n";
if (CARS_RED == COLORS_RED) std::cout << "true\n"; // WARNING ONLY
return 0;
}
Для решения этих проблем используют enum class (перечисления с областью видимости):
// теперь разные enum могут содержать одинаковые названия перечислителей
enum class Colors
{
RED,
GREEN,
BLUE
};
enum class Cars
{
RED,
GREEN,
BLUE
};
int main()
{
// вместо префикса теперь название пространства имен
int x = Colors::RED; // ERROR
Colors y = Colors::RED; // OK
if (Colors::RED == Cars::RED) {} // ERROR, разные типы
if (y == Colors::RED) {} // OK
return 0;
}