Last modified: March 19, 2026

This article is written in: 🇵🇱

Typ wyliczeniowy enum w C++

Typ wyliczeniowy (enum) pozwala opisać zamknięty zbiór możliwych wartości pod czytelnymi nazwami. Zamiast “magicznych liczb” (np. 0,1,2) używasz sensownych identyfikatorów (Poniedzialek, Wtorek), co poprawia czytelność i zmniejsza liczbę błędów.

W C++ występują dwie główne odmiany:

Klasyczny enum

Klasyczny enum tworzy zestaw nazwanych stałych, które domyślnie mają wartości całkowite zaczynające się od 0 i rosnące o 1.

Podstawowy przykład

enum DzienTygodnia { Poniedzialek, Wtorek, Sroda, Czwartek, Piatek, Sobota, Niedziela };

int main() {
    DzienTygodnia dzien = Poniedzialek; // nazwy trafiają do “globalnej” przestrzeni nazw
}

Wygoda, ale i ryzyko: automatyczne konwersje

W klasycznym enum wartości często da się łatwo mieszać z int-em (zależnie od kontekstu i kompilatora), co bywa źródłem błędów.

enum Tryb { Off, On };

int main() {
    Tryb t = On;
    int x = t;   // często działa: implicit enum -> int
}

Kolizje nazw

Nazwy elementów klasycznego enum “wychodzą” na zewnątrz, więc łatwo o konflikt:

enum Kolor { Czerwony, Zielony };
enum Swiatlo { Zielony, Czerwony }; // BŁĄD: powtórzone nazwy w tym samym zakresie

Ręczne wartości (np. pod protokoły / pliki / API)

enum HttpStatus {
    OK = 200,
    NotFound = 404,
    ServerError = 500
};

enum class (zalecany wariant)

enum class wprowadza silne typowanie i enkapsulację nazw. To znaczy:

Podsta wowy przykład

#include <iostream>

enum class Kolor { Czerwony, Zielony, Niebieski };

int main() {
    Kolor k = Kolor::Czerwony;

    switch (k) {
        case Kolor::Czerwony: std::cout << "Czerwony\n"; break;
        case Kolor::Zielony:  std::cout << "Zielony\n";  break;
        case Kolor::Niebieski:std::cout << "Niebieski\n";break;
    }
}

Brak “przypadkowego int-a”

enum class Tryb { Off, On };

int main() {
    Tryb t = Tryb::On;
    // int x = t; // BŁĄD: brak niejawnej konwersji
}

Jeśli naprawdę potrzebujesz liczby, rób to jawnie:

#include <type_traits>

int x = static_cast<int>(Tryb::On);

Typ bazowy (rozmiar i kompatybilność)

Zarówno enum, jak i enum class mogą mieć określony typ bazowy. To przydaje się, gdy:

#include <cstdint>

enum class Wielkosc : std::uint8_t { Mala, Srednia, Duza };

int main() {
    Wielkosc w = Wielkosc::Srednia;
}

Praktyczne zastosowania

Stany programu / maszyny stanów

enum class Stan { Uruchomiony, Zatrzymany, Wstrzymany };

void zmienStan(Stan s) {
    // ...
}

Kody błędów z ręcznymi wartościami

enum class Blad : int {
    Brak = 0,
    Ostrzezenie = 1,
    Krytyczny = 2
};

Blad b = Blad::Krytyczny;

Enum w klasie/strukturze (porządek i brak konfliktów)

struct Samochod {
    enum class Typ { Sedan, Kombi, Hatchback };
    Typ typ;
};

int main() {
    Samochod s;
    s.typ = Samochod::Typ::Sedan;
}

Kiedy używać czego?

Jeśli chcesz, mogę dopisać krótką sekcję o: