Перечисления (enum) используются в C++ для создания констант. Допустим надо объявить константы для музыкальных нот и каждую инициализировать соответствующим порядковым номером. Можно воспользоваться уже знакомым нам способом:
Такое объявление занимает много строк кода и не совсем удобно. Используя перечисление, можно определить эти константы иным способом. Синтаксис enum похож на синтаксис структур: ключевое слово – дескриптор – элементы в фигурных скобках через запятую :
Это полная форма – с дескриптором (именем перечисления). Как и в случае со структурами, имя перечисления можно не использовать:
В первом случае – мы сможем создавать переменные типа перечисления notes. Во втором случае – нет.
Обратите внимание, что значение 1 было присвоено только первому элементу перечисления. По умолчанию первому элементу в фигурных скобках присваиваются значение 0, второму на единицу больше (1), третьему на единицу больше второго (2) и т.д. Но если явно задать значение, как в примере, то увеличение на единицу начнется с этого числа. Покажем на экран значения некоторых элементов перечисления.
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include <iostream> using namespace std; enum notes{ DO = 1, RE, MI, FA, SOL, LA, SI }; int main() { setlocale(LC_ALL, "rus"); cout << DO << ' ' << RE << ' ' << SOL << endl; return 0; } |
Хоть мы и не присваивали явно значения RE и SOL – они хранят правильные порядковые номера нот.
Имена перечислителей (элементов перечисления) должны быть уникальными. Значения же могут совпадать:
1 | enum champions{ KLICHKO_VITALIY = 1, KLICHKO_VLADIMIR = 1, CHISORA, ADAMEK }; |
Значение 1 будут хранить KLICHKO_VITALIY и KLICHKO_VLADIMIR. 2 запишется в CHISORA, 3 – в ADAMEK . В элементы перечисления могут быть записаны только целые числа. Изменить ниже в программе значения, которые присвоены элементам в фигурных скобках нельзя. Если создается переменная типа перечисления – она может принять значение только одного из своих элементов:
На картинке видно, что записать число в переменную типа champions возможности нет. Можно записать только именованную константу, которая объявлена во время определения enum.
Для закрепления рассмотрим пример. В нём создадим перечисление levelsName. Оно будет содержать шесть элементов – “названия” этажей. Пользователю предложим “покататься” на лифте.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | #include <iostream> using namespace std; enum levelsName { parking, bank, insurance, exchange, showroom, Restaurant }; int main() { setlocale(LC_ALL, "rus"); int floor = parking; // выбор пользователя - номер этажа int exitOrNot = 1; // выйти или нет while (exitOrNot == 1) { cout << "Номер этажа (0,1,2,3,4,5): "; cin >> floor; switch (floor) { case(parking) : cout << "\a\a\aВы в паркинге!\n\n"; break; case(bank) : cout << "\a\a\aПервый этаж!"; cout << "\nЗдесь находится Креди Агриколь Банк.\n\n"; break; case(insurance) : cout << "\a\a\aВторой этаж!"; cout << "\nСтраховая компания UNICA.\n\n"; break; case(exchange) : cout << "\a\a\aТретий этаж!"; cout << "\nФондовая биржа.\n\n"; break; case(showroom) : cout << "\a\a\aЧетвёртый этаж!"; cout << "\nВыставочный зал и зал для презентаций.\n\n"; break; case(Restaurant) : cout << "\a\a\aПятый этаж!"; cout << "\nРесторан Sky.\n\n"; break; default: cout << "\a\a\aОшибка!\n\n"; } cout << "Выйти из лифта - нажмите 0.\n"; cout << "Выбрать другой этаж - нажмите 1: "; do { cin >> exitOrNot; } while (exitOrNot != 0 && exitOrNot != 1); cout << endl; } return 0; } |
Объявляем целочисленную переменную floor в строке 10 и инициализируем ее именованной константой parking. Так floor примет значение 0. В строке 13 входим в цикл while. Пока пользователь не введет в переменную exitOrNot значение 0, программа будет ему предлагать “кататься на лифте” – выбрать номер этажа.
После каждого выбора этажа звучит сигнал (три коротких гудка) и на экран выводится номер этажа и информация о том, что на нём размещено. Это реализовано оператором выбора switch. Его блоки case перебирают элементы перечисления. То есть пользователь вводит целое число, а case ищет, какому из элементов перечисления оно соответствует.
Например, если введено 5 – это соответствует значению элемента Restaurant – на экран выводится соответствующее сообщение.
Результат:
Посмотрите короткое видео о перечислениях C++.
Нормальные примеры, а статью не читал.
Я сформулирую, а ты поправь пожалуйста, если со статьей я разойдусь в чем-то.
1) Магические числа – это плохо, чтобы избавиться от них используют константы.
2) Константы – это хорошо, но константы сильно связаны друг с другом.
Пример: в программе у нас есть юнит. Юнит может быть магом, гоблином или эльфом. Одним из вариантов реализации этого могло быть что-то такое:
const int Mag = 1;
const int Goblin = 2;
const int Elf = 3;
struct Unit {
string name;
int unit_type;
};
Очевидно, это плохо, потому что:
2.1) константы Mag, Goblin, Elf доступны всем, т.е. засоряют пространство имен;
2.2) константы могут быть случайно использованы в неправильном контексте, ведь они не сгруппированы, т.е. ничем не отличаются от других констант;
2.3) полю unit_type можно присвоить неправильное значение (компилятор не сообщит нам об ошибке) :
unit.unit_type = -123;
2.4) нам надо придумывать самим значения константам и следить чтобы они не повторялись.
Все эти проблему эротично решает enum:
enum UnitType { Mag, Goblin, Elf };
struct Unit {
unit_type type;
string name;
};
обратиться к константам мы можем как напрямую (Mag) так и по имени перечисления (UnitType::Mag). Второй вариант обозначает явно контекст, но вроде бы появился в С++11 (раньше его поддерживало большинство компиляторов, но стандарту вроде как оно не соответствовало).
unit.unit_type = 123;
завершится ошибкой на этапе компиляции (т.е. очень рано). А если вы юзаете современную IDE – то еще раньше (среда разработки подчеркнет ошибку).
Ну и значения им присвоены автоматически, следить за этим не надо.
Код можно сделать чуть красивей:
struct Unit {
unum Type {Mag, Goblin, Elf} type;
string name;
};
Это может быть лучше, т.к. видно, что Unit и Type неразрывно связаны (раньше мы кодировали это в имени UnitType). Кодировать что-то в имени не очень хорошо, например если бы Unit переименовали бы в Item – то нам пришлось бы переименовывать ItemType, или связь стала бы не очевидна.
Unit::Type::Mag лаконично задает контекст, в котором может использоваться константа.
Ну а еще unum активно используется с шаблонами, но это совсем другая тема. Ты ее раскроешь? )
Мой вариант решения задачки из примера:
pre class=”lang:c++ decode:true ”
#include
using namespace std;
int main()
{
setlocale(LC_ALL, “rus”);
enum lewels {undParking = -1, oneFloor = 1, secondFloor = 2, Restaurant = 3, Penthaus = 4};
int lift = 0;
int exit = 1;
cout <<"Вы зашли в здание и сейчас находитесь на " << oneFloor << " этаже \n";
do
{
cout <> lift;
switch (lift)
{
case(undParking):
cout << "Вы попали в подземную автостоянку \n";
break;
case(oneFloor):
cout << "Вы на первом этаже \n";
cout <> exit;
if (exit == 0)
{
cout << "Вы вышли из здания \n";
}
break;
case(secondFloor):
cout << "Вы на втором этаже \n";
break;
case(Restaurant):
cout << "Вы в ресторане \n";
break;
case(Penthaus):
cout << "Вы в пентхаусе \n";
break;
default:
cout << "Нет такого этажа \n";
}
} while (exit == 1);
return 0;
}
/pre
Перечисления в языке C++ прямо наследуют поведение перечислений языка C, за исключением того, что перечисляемый тип в C++ — настоящий тип, и ключевое слово
Цитата из описания языков C и C++:
> В версии С89 определено 32 ключевых слова.
> …
> enum — Пользовательский тип данных “перечисляемый тип”
> …
> В языке C++ содержатся все ключевые слова, определенные в версии С89, а также следующие.
И где здесь различие?
Если для каждого случая перечисления задано значение (известное как значение “raw”), это значение может быть строкой, символом или значением любого целого числа или типа с плавающей запятой.