Typ wyliczeniowy

   Żonglowanie milionem cyferek w programie to niezbyt ciekawe zajęcie i nietrudno się w tych wszystkich cyferkach pogubić. Przykładowo masz kilka liczb oznaczających wynik gry. Zero oznacza, że gra się nie odbyła, jedynka że wygrał gracz pierwszy, dwójka że wygrał gracz drugi, no i trójka oznaczająca remis. Cztery liczby to może nie jest jeszcze zbyt dużo, choć i tyle łatwo pomylić będąc już gdzieś głęboko w kodzie. Dużo łatwiej by było, gdyby zamiast cyfr posługiwać się jakimiś ich nazwami, co nie? ;-)   Najprostszym wyjściem jest użycie dyrektywy kompilatora #define, która może przyporządkować liczbie nazwę. Robimy więc tak:
#define WYNIK_GRY_NIE_BYLO 0 #define WYNIK_WYGRAL_GRACZ_1 1 #define WYNIK_WYGRAL_GRACZ_2 2 #define WYNIK_REMIS 3 Teraz możesz posugiwać się nazwą liczby, zamiast bezpośrednio liczbą. Takie definicje są czymś w rodzaju stałych typu int, ale mają jedną poważną wadę: w debuggerze [specjalny program do wykrywania błędów] nie pokazują się ładne nazwy, tylko dalej nic nie znaczące liczby. Lepiej więc jest używać normalnych stałych. Na przykład tak:
const int WYNIK_GRY_NIE_BYLO = 0; const int WYNIK_WYGRAL_GRACZ_1 = 1; const int WYNIK_WYGRAL_GRACZ_2 = 2; const int WYNIK_REMIS = 3; Ten sposób jest lepszy, bo w debuggerze pokaże nam się nie tylko wartość, ale też nazwa zmiennej [a raczej stałej]. Ale to dalej nie jest to, czego byśmy chcieli. Dajmy na to masz funkcję, która sprawdza wynik gry. Powinna ona przyjmować tylko wspomniane wyżej wartości od 0 do 3. Oczywiście wrzucenie tam liczby 20 jest błędem i kompilator powinien nas o tym powiadomić. Co zrobić, żeby tak było?

   Do tego celu wymyślono właśnie typ wyliczeniowy. Jest on jakby zbiorem kolejnych liczb, z których każda ma swoją etykietkę. Zobacz, jak moglibyśmy z jego pomocą zdefiniować nowy typ, będący naszym wynikiem gry:
enum WynikGry = {Nieodbyta=0, Wygral1, Wygral2, Remis}; Jeśli teraz zdefiniujesz zmienną typu WynikGry, to będzie ona mogła przyjmować tylko wartości znajdujące się w tym zbiorze, a więc Nieodbyta, Wygral1, Wygral2, albo Remis. Gdy spróbujesz przypisać takiej zmiennej wartość spoza dopuszczalnego zbioru, na przykład tak:
WynikGry wyniczek = 54; to kompilator powinien zaprotestować. Protest ten różnie wygląda w różnych kompilatorach, na przykład kompilator Borland Turbo C++ wyświetla jedynie ostrzeżenie. Typ wyliczeniowy jest traktowany jak stała typu int, więc można przypisywać tak jak poniżej:
int inny_wynik = Remis; a nawet używać typu wyliczeniowego w pętli for [i nie tylko], w instrukcjach warunkowych, a także przesyłać go jako parametr do funkcji. Omówienia wymaga jeszcze tylko ten znak = w definicji typu. Normalnie numerowanie etykiet w typie wyliczeniowym zaczyna się od zera, więc właściwie to "=0" nie jest potrzebne. Jednak nie zapomnij, że można zacząć numerację od innej liczby, a nawet zmienić numerację gdzieś w środku zbioru i np. zacząć liczyć od 50 wzwyż :-). Typy wyliczeniowe przydają się wtedy, gdy jakaś wartość może przyjmować tylko kilka różnych stanów, które chcielibyśmy mieć jakoś nazwane.

   Ta lekcja może nie była zbyt ciekawa ani nawet długa, a zrobiłem ją tylko po to, żeby niczego nie pominąć. Po prostu dobrze jest czasem wiedzieć, że w C++ jest coś takiego jak typ wyliczeniowy ;-J. Następna lekcja będzie już ciekawsza, obiecuję ;-).