enum în C++

Tipuri de date C++98 (enum class: C++11)

Definește un tip cu o listă fixă de valori cu nume, de exemplu zilele săptămânii sau stările unei comenzi.

Sintaxă
enum Culoare { rosu, verde, albastru };
enum class Stare { activ, blocat };          // C++11, recomandat
enum class Nota : char { slab = 'F', bun = 'B' };

Ce face enum

Un enum (enumerare) creează un tip ale cărui valori sunt nume: Stare::activ este mult mai clar decât un număr magic 1. În spate, fiecare valoare este un număr întreg, pornind de la 0, dacă nu îi dai altă valoare.

Forma recomandată este enum class (C++11): valorile se scriu cu prefix (Stare::activ), nu se amestecă cu alte nume și nu se transformă singure în int. Pentru număr folosești static_cast<int> sau std::to_underlying (C++23).

Varianta veche, enum simplu, pune valorile direct în spațiul înconjurător și se transformă automat în int, ceea ce poate ascunde greșeli.

Exemple

Exemplul 1: enum class într-un switch

#include <print>

enum class StareComanda { noua, platita, livrata, anulata };

const char* descrie(StareComanda s) {
    switch (s) {
        case StareComanda::noua: return "Comanda a fost primită";
        case StareComanda::platita: return "Plata a fost confirmată";
        case StareComanda::livrata: return "Coletul a ajuns";
        case StareComanda::anulata: return "Comanda a fost anulată";
    }
    return "Stare necunoscută";
}

int main() {
    StareComanda comanda = StareComanda::platita;
    std::println("{}", descrie(comanda));
    comanda = StareComanda::livrata;
    std::println("{}", descrie(comanda));
}

Rezultat

Plata a fost confirmată
Coletul a ajuns

Exemplul 2: Valori numerice și tip de bază

Poți alege valorile și tipul întreg din spate (: char). std::to_underlying (din <utility>, C++23) dă valoarea numerică.

#include <print>
#include <utility>

enum class Prioritate : char { mica = 1, medie = 5, mare = 10 };

int main() {
    Prioritate p = Prioritate::medie;
    std::println("Valoare: {}", static_cast<int>(p));
    std::println("Valoare: {}", static_cast<int>(std::to_underlying(Prioritate::mare)));
    std::println("Mărime: {} octet", sizeof(Prioritate));
}

Rezultat

Valoare: 5
Valoare: 10
Mărime: 1 octet

Exemplul 3: enum clasic (fără class)

Valorile se pot folosi fără prefix și devin automat int: marti este 1.

#include <print>

enum Zi { luni, marti, miercuri, joi, vineri };

int main() {
    Zi azi = miercuri;
    int numar = azi;
    std::println("Miercuri are numărul {}", numar);
    std::println("Zile lucrătoare: {}", vineri + 1);
}

Rezultat

Miercuri are numărul 2
Zile lucrătoare: 5

Greșeli frecvente

  • Definești două enum-uri clasice cu aceeași valoare (enum Semafor { rosu }; și enum Culoare { rosu };). Numele se ciocnesc; cu enum class problema dispare.
  • Încerci int x = Stare::activ; cu un enum class. Nu există conversie automată; scrie static_cast<int>(Stare::activ).
  • Transformi un număr oarecare în enum (static_cast<Zi>(42)) și apoi îl folosești într-un switch fără default. Nicio ramură nu se potrivește; validează numărul întâi.

Comenzi înrudite

  • switch, case, default: Alege una dintre mai multe ramuri după valoarea unei expresii întregi, a unui caracter sau a unui enum.
  • using: Aduce nume dintr-un spațiu de nume în locul curent sau creează un nume nou (alias) pentru un tip existent.
  • static_cast, dynamic_cast, const_cast, reinterpret_cast: Cele patru conversii explicite: static_cast (obișnuite), dynamic_cast (clase), const_cast (const) și reinterpret_cast (biți).
  • union: Un tip în care toți membrii împart aceeași zonă de memorie; la un moment dat doar unul dintre ei are o valoare validă.
  • std::to_underlying: Transformă o valoare de enumerare (inclusiv enum class) în numărul întreg din spatele ei.