Урок №61. Перерахування (перелічуваний тип даних)

  Юрій  | 

  Оновл. 15 Тра 2020  | 

 195

C++ дозволяє програмістам створювати свої власні (користувацькі) типи даних.

Перелічуваний тип даних

Перерахування (або ще “перелічуваний тип даних“) — це тип даних, де будь-яке значення (або ще “енумератор/елемент“) визначається як символьна константа. Оголосити перерахування можна за допомогою ключового слова enum. Наприклад:

Оголошення перерахувань не вимагає виділення пам’яті. Тільки коли змінна перелічуваного типу визначена (наприклад, як змінна paint в прикладі вище), тільки тоді виділяється пам’ять для цієї змінної.

Зверніть увагу, кожен енумератор розділяється комою, а саме перерахування закінчується крапкою з комою.

Примітка: До C++11, кінцева кома після останнього елементу (як після COLOR_PURPLE в прикладі вище) була заборонена (хоча не всі компілятори на це скаржились). Однак, починаючи з C++11, кінцева кома дозволена.

Імена перерахувань

Імена перерахувань часто починаються з великої літери, а імена елементів взагалі складаються тільки з великих букв. Оскільки елементи знаходяться в одному і тому ж просторі імен, що і саме перерахування, то одне і те ж ім’я одного енумератора не може бути використано в кількох перерахувань одного і того ж простору імен:

Також поширено додавання назви перерахування в якості префіксу до його елементів, наприклад: ANIMAL_ чи COLOR_ — як для запобігання конфліктів імен, так і з метою коментування коду.

Значення енумераторів

Кожному енумератору автоматично присвоюється цілочисельне значення в залежності від його позиції в списку перерахування. За замовчуванням, першому елементу присвоюється ціле число 0, а кожному наступному — на одиницю більше, ніж попередньому:

Результат виконання програми:

4

Можна й самому визначати значення елементів. Вони можуть бути як додатними, так і від’ємними, або взагалі мати аналогічні іншим елементам значення. Будь-які енумератори, що не визначені вами, — матимуть значення на одиницю більше, ніж значення попередніх елементів. Наприклад:

Зверніть увагу, ANIMAL_HORSE і ANIMAL_ZEBRA мають однакові значення. Хоча C++ це не забороняє, присвоювати одне значення декільком енумераторам в одному перерахуванні не рекомендується.

Порада: Не присвоюйте свої значення енумераторам.

Правило: Не присвоюйте однакові значення двом енумераторам в одному перерахуванні, якщо на це немає вагомої причини.

Обробка перерахувань

Оскільки значеннями енумераторів є цілі числа, то їх можна присвоювати цілочисельним змінним, а також виводити в консоль (як змінні типу int):

Результат виконання програми:

6

Компілятор не буде неявно конвертувати цілочисельне значення в значення енумератора. Наступне викличе помилку компіляції:

Тим не менш, ви можете зробити подібне за допомогою оператора static_cast:

Компілятор також не дозволить вам вводити енумератори через std::cin:

Однак, ви можете ввести ціле число, а потім використати оператор static_cast, щоб помістити цілочисельне значення в перелічуваний тип:

Кожен перелічуваний тип вважається окремим типом. Отже, спроба присвоїти енумератор з одного перерахування енумератору з іншого — викличе помилку компіляції:

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

Виведення енумераторів

Спроба вивести енумератор за допомогою std::cout призведе до виведення цілочисельного значення самого енумератора (тобто його порядкового номера). Але як вивести значення енумератора у вигляді тексту? Один із способів — написати функцію з використанням стейтментів if:

Виділення пам’яті для перерахувань

Перелічувані типи вважаються частиною сімейства цілочисельних типів, і компілятор сам визначає, скільки пам’яті виділяти для змінних типу enum. Офіційно, C++ повідомляє, що розмір перерахування повинен бути досить великим, щоб мати можливість вмістити всі енумератори. Але найчастіше розміри змінних enum будуть такими ж, як і розміри звичайних змінних типу int.

Оскільки компілятору потрібно знати, скільки пам’яті виділяти для перерахування, то використовувати попереднє оголошення з ним ви не зможете. Однак існує простий обхідний шлях. Оскільки визначення перерахування саме по собі не вимагає виділення пам’яті і якщо перерахування необхідно використовувати в декількох файлах, то його можна визначити в заголовковому файлі і підключати цей заголовок всюди, де необхідно використовувати перерахування.

Користь від перерахувань

Перелічувані типи неймовірно корисні для документації коду і поліпшення читабельності.

Наприклад, функції часто повертають цілі числа назад в викликаючу функцію в якості кодів помилок, якщо щось пішло не так. Як правило, невеликі від’ємні числа використовуються для представлення можливих кодів помилок. Наприклад:

Однак магічні числа, як в прикладі вище, — не дуже ефективне рішення. Альтернативним рішенням є використання перерахувань:

Це і читати легше, і зрозуміти простіше. Крім того, функція, яка викликає іншу функцію, може перевірити значення, що повертається на відповідний енумератор. Це краще, ніж самому порівнювати результат, який повертається, з конкретними цілочисельними значеннями, щоб зрозуміти яка саме помилка сталася, чи не так? Наприклад:

Перелічувані типи найкраще використовувати при визначенні набору пов’язаних ідентифікаторів. Наприклад, припустимо, що ви пишете гру, в якій гравець може мати один предмет, але цей предмет може бути декількох різних типів:

Або, якщо ви пишете функцію для сортування групи значень:

Багато мов програмування використовують перерахування для визначення логічних значень. По суті, логічний тип даних — це просте перерахування всього лише з двома енумераторами: true і false! Однак в C++ значення true і false визначені як ключові слова замість енумераторів.

Тест

Завдання №1

Напишіть перерахування з наступними енумераторами: ogre, goblin, skeleton, orc і troll.

Відповідь №1

Завдання №2

Оголосіть змінну перелічуваного типу, який ви визначили в завданні №1, і присвойте їй тип ogre.

Відповідь №2

Завдання №3

Правда чи брехня:

Енумераторам можна:

   присвоювати цілочисельні значення;

   не присвоювати значення;

   явно присвоювати значення типу з плаваючою крапкою;

   присвоювати значення попередніх енумераторів (наприклад, COLOR_BLUE = COLOR_GRAY).

Енумератори можуть бути:

   від’ємними;

   не унікальними.

Відповідь №3

Енумераторам можна:

   Правда.

   Правда. Енумератору без значення буде неявно присвоєно цілочисельне значення попереднього енумератора +1. Якщо попереднього енумератора немає, то тоді присвоїться значення 0.

   Брехня.

   Правда. Оскільки значеннями енумераторів є цілі числа, а цілі числа можна присвоювати енумераторам, то одні енумератори можуть бути присвоєні іншим енумераторам (хоча цього краще уникати).

Енумератори можуть бути:

   Правда.

   Правда.

Оцінити статтю:

1 Зірка2 Зірки3 Зірки4 Зірки5 Зірок (1 оцінок, середня: 5,00 з 5)
Loading...

Залишити відповідь

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