Menu
Coddy logo textTech

Enum Classes и строгая типизация

Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 80 из 104.

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

У традиционных перечислений есть проблемы: их значения проникают в окружающую область видимости и неявно преобразуются в целые числа, что приводит к трудноуловимым ошибкам:

// Традиционный enum — проблематичный
enum Color { Red, Green, Blue };
enum TrafficLight { Red, Yellow, Green };  // Ошибка! Red и Green уже определены

int x = Red;  // Неявно преобразуется в int (0)
if (Red == 0) { }  // Компилируется — сравнение enum с int

Перечисления enum class решают эти проблемы, ограничивая область видимости значений и предотвращая неявные преобразования:

enum class Color { Red, Green, Blue };
enum class TrafficLight { Red, Yellow, Green };  // OK - нет конфликта

Color c = Color::Red;      // Необходимо использовать оператор области видимости
// int x = c;              // Ошибка! Нет неявного преобразования
int x = static_cast<int>(c);  // Требуется явное преобразование

// if (c == 0) { }         // Ошибка! Нельзя сравнивать с int
if (c == Color::Red) { }   // OK - сравнение одинаковых типов

Вы также можете указать базовый тип для управления памятью:

enum class Status : uint8_t {
    Inactive = 0,
    Active = 1,
    Pending = 2
};

Классы Enum хорошо интегрируются с проектированием в стиле ООП, делая код более читаемым и выявляя ошибки типов во время компиляции, а не во время выполнения.

challenge icon

Задание

Легко

Давайте создадим систему приоритетов задач, которая использует классы enum для представления различных уровней приоритета и статусов задач. Это демонстрирует, как классы enum обеспечивают безопасность типов и предотвращают такие bug, которые возникают при использовании традиционных enum.

Вы организуете код в трех файлах:

  • TaskTypes.h: Define классы enum для системы задач.

    Создайте класс enum Priority со значениями: Low, Medium, High и Critical. Укажите int в качестве базового типа, со значениями 1, 2, 3 и 4 соответственно.

    Создайте класс enum Status со значениями: Pending, InProgress и Completed.

    Предоставьте две вспомогательные функции:

    • priorityToString(Priority p): возвращает приоритет в виде строки ("Low", "Medium", "High" или "Critical")
    • statusToString(Status s): возвращает статус в виде строки ("Pending", "InProgress" или "Completed")
  • Task.h: Define класс Task, который использует ваши классы enum.

    Ваш Task должен хранить имя (строку), Priority и Status. constructor должен принимать имя и приоритет, при этом статусом по умолчанию должен быть Status::Pending.

    Реализуйте следующие методы:

    • setStatus(Status s): обновляет статус задачи
    • getPriorityValue(): возвращает базовое целочисленное значение приоритета с использованием static_cast
    • display(): выводит задачу в формате: [name] - Priority: [priority] (Value: [value]) - Status: [status]
  • main.cpp: Считайте три входных значения:
    1. Имя задачи (строка)
    2. Уровень приоритета в виде целого числа (1=Low, 2=Medium, 3=High, 4=Critical)
    3. Status в виде целого числа (0=Pending, 1=InProgress, 2=Completed)

    Создайте Task с указанными именем и приоритетом (преобразуйте целое число в соответствующее значение enum Priority с использованием static_cast). Затем установите его статус на основе третьего входного значения. Наконец, вызовите display(), чтобы показать детали задачи.

Например, для входных значений Fix bug, 3 и 1:

Fix bug - Priority: High (Value: 3) - Status: InProgress

Для входных значений Write docs, 1 и 2:

Write docs - Priority: Low (Value: 1) - Status: Completed

Для входных значений Deploy app, 4 и 0:

Deploy app - Priority: Critical (Value: 4) - Status: Pending

Обратите внимание, как классы enum полностью разделяют значения приоритета и статуса. Вы не можете случайно сравнить Priority с Status или присвоить одно другому. Явный static_cast, необходимый для преобразования между целыми числами и значениями enum, делает назначение кода понятным и предотвращает трудно обнаружимые bug.

Попробуйте сами

#include <iostream>
#include <string>
#include "Task.h"

using namespace std;

int main() {
    // Прочитать входные данные
    string taskName;
    int priorityInt;
    int statusInt;
    
    getline(cin, taskName);
    cin >> priorityInt;
    cin >> statusInt;
    
    // TODO: Создайте Task с заданным именем и приоритетом
    // Используйте static_cast для преобразования priorityInt в enum Priority
    
    // TODO: Установите статус задачи на основе statusInt
    // Используйте static_cast для преобразования statusInt в enum Status
    
    // TODO: Вызовите display() для отображения деталей задачи
    
    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C++