Typ wyliczeniowy/enum w C++

0

Witajcie.
Proste pytanie,istnieje takie coś jak Enum/typ wyliczeniowy w C++. Nie rozumiem dokładnie jak on działa/się go stosuje,niby widzę w książce jak on wygląda,jego właściwości (troszkę ubogo opisane w księdze zaklęć,ale cóż),ale nie rozumiem,próbuje u siebie na kodzie,ale błędy i błędy,nie działa,nie kompiluje się.Gdzie się to cudo stosuje,jak często i w jakich sytuacjach? Mój poziom C++ oceniam na średni,podstawy znam,wgłębiam w się ciemniejsze strony tego że języka.Jakiś filmik,przykład,fajnie by było ;)

2

To typ wyliczeniowy, używasz go jak gdy oczekujesz że dany obiekt ma przyjmować tylko konkretne (najczęściej nazwane) wartości.

0

A jakiś przykład? Nawet gdybym chciał się nim pobawić to nie mogę,bo kompilator mi błędy pokazuje.Prosty przykład daj z użyciem enuma.Łopatologicznie wytłumacz,W skali 1-10,jak często się go używa czy powinno?

3

Powiedzmy że masz w systemie wielu użytkowników. Mogą mieć oni rangę admina, zwykłego użytkownika i gościa. Wtedy mógłbyś np. użyć

enum class role
{
    admin,
    member,
    guest,
};
0

No dobra to zrozumiałe,ale jak powiedzmy chce użyc gdzieś w kodzie ten typ wyliczeniowy.To jak zrobić? Bo tutaj kończy się moje działanie z tym,bo jak chce jakoś przypisać do zmiennej czy nawet pod switcha rzucić to nie działa.

1

może inaczej. Ja uważam, że typy wyliczeniowe zwiększają czytelność i jasność kodu jeżeli chodzi o pewnego rodzaju czynności jakie ma wykonać. Np.

enum {admin=0, user=1};

//gdzieś tam dalej

if(admin){
  //loguj z prawami admina
}
else if(user){
  //loguj z prawami usera
}

w tych warunkach równie dobrze mógłbyś wpisać liczby, zamiast słów z typu wyliczeniowego - enum to według mnie takie udogodnienie które zwiększa przejrzystość w kodzie.

2

Np w SFML typ sf::Key reprezentuje wciśnięty klawisz, np sf::Keyboard::Right to prawa strzałka a sf::Keyboard::L to klawisz z literą "L". Funkcja isKeyPressed (Key key) sprawdza, czy podany klawisz jest wciśnięty, zatem można pisać kod jak tu

if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
    // move left...
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
    // move right...
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
{
    // quit...
}
0

No kodu na ten moment nie mam,zirytowałem się i zamknąłem kompilator.Ale dajmy przykład.

enum colors{       
           blue,
           red,
           white
};
colors c1; ///deklaruje typ wyliczeniowy

///  i co teraz?
/// użycie np c1=blue lub c1=1 , chce powiedzmy przypisać jemu kolor red,czyli int o wartości 1.
/// No jak tutaj zadziałać,by np. switch(c1) i powiedzmy case 1: wypisze red, case 0: blue,
// no wiadomo,tutaj coś mnie blokuje,w książce prawdzie mówiąc nie pokazali żadnego przykładu jak to zastosować i człowiek nie wie :/ 
2

Przypisujesz do c1 albo colors::red, albo colors::red albo colors::white. W rodzaju

#include <iostream>

enum class UnitType {
    Knight,
    Archer,
    Axeman,
};

int main()  {
    UnitType unit;

    unit = UnitType::Knight;
    switch(unit) {
    case UnitType::Knight:
        std::cout << "Knight\n";
    break;
    case UnitType::Archer:
        std::cout << "Archer\n";
    break;
    case UnitType::Axeman:
        std::cout << "Axeman\n";
    break;
    }
}
4

Dlaczego liczba mnoga? c1 przechowuje tylko jeden kolor. Enum służy do tego, aby ograniczyć możliwy zakres wartości oraz wybranym wartościom nadać czytelną dla człowieka nazwę. Dzięki czemu nie masz w kodzie magicznych liczb, i nie sprawdzasz czy c1 == 2, tylko czy c1 == color::red.

0

inaczej, przykład z Qt

enum { CityName=0, CityCountry=1, CityPopulation=2, CityArea=3, CityCountryFlag=4 };

zrobiłeś sobie typ wyliczeniowy i pora na jego użycie gdzieś w kodzie

 while(!row.isNull()) {

// (...)
        City *city = new City();
        city->name = data.at(CityName);
        city->country = data.at(CityCountry);
        city->population = data.at(CityPopulation).toInt();
        city->area = data.at(CityArea).toFloat();
// (...)
    }

Po prostu traktuj to jako swoistego rodzaju "podpowiedź" w miejscu gdzie użyłeś typu wyliczeniowego, zamiast się zastanawiać co ta cyferka robiła...

0

Dobra,mniej więcej ogarniam co i jak.Znacie może jakieś filmy na yt z tego? Nie musi być po polsku,ale wytłumaczone,byłbym wdzięczny

1

Enumy są bardzo proste i nie szukaj w nich czegoś bardziej skomplikowanego. Po prostu taki dziwny typ wyliczeniowy. Też miałem problem z zrozumieniem go na początku ale zacząłem zauważać ich siłę w realnym kodzie. Myślę że jak natrafisz na jakiś problem gdzie będziesz chciał mieć posegregowaną odpowiednią formę działania dla konkretnego przypadku to samoistnie użyjesz enuma.

0

Chyba nie wypłynęło w wątku.

Pewnego rodzaju "prawie typesafe" integer (zwykle mały integer).
Jednak od stałych const typu int (czyli już jest dobrze, bo mamy nazwę zamiast magicznych cyferek), które są dalej typu int, różni się tym, że tutaj powstaje nowy typ.
Oczekiwana jest zgodność zmiennej typu "jakiś enum" z wartością jaka jest podstawiana itd...
Piszę "prawie typesafe" bo reliktem C/C++ jest wymienność np bool/integer czy właśnie enum / intgeger.
Tym niemniej kompilatory dają ostrzeżenia.

W C# czy Javie są to typy w pełni rozdzielone, to mi się najbardziej podoba - ale te języki nie były zobowiązane do kompatybilności z całą przeszłością.

1
typek_typek123 napisał(a):

No kodu na ten moment nie mam,zirytowałem się i zamknąłem kompilator.Ale dajmy przykład.

colors c1; /// ~~deklaruje typ wyliczeniowy~~

Typ wyliczeniowy masz wcześniej. Tu deklarujesz zmienną typu wyliczeniowego.

0

podlinkuję ci kilka artykułów na ten temat niestety po angielsku

link 1

link 2

link 3

w drugim z linków z grubsza jest opisane po co się typów wyliczeniowych używa no ale to jest tylko mały zalążek tematu

polecam też dobrą książkę, najlepiej zacząć od Pozycji 1

  1. Opus magnum C++ 11
  2. Programowanie. Teoria i praktyka z wykorzystaniem C++
0

warto dodać o automatycznej numeracji kolejnych pól enuma, bo to czasami jest wystarczającym powodem na jego zastosowanie:

#include <iostream>

enum ee {
   dziesiec = 10,
   jedenascie,
   dwanascie
   //...
};

int main() {
    std::cout << ee::dziesiec << ", "
         << ee::jedenascie << ", "
         << ee::dwanascie
         << std::endl;

    return 0;
}
3

Dobrą praktyką jest używanie silnych typów wyliczeniowych enum class. Zapobiega to przypadkowym niejawnym konwersjom w kodzie zobacz. Dodatkowo silne typy wyliczeniowe można deklarować bez określania ich wewnętrznego typu zmiennych underlying_type.

enum class Color; // ok
enum Color; // compile time error
enum Color : int; // ok

Poniżej mały przykład użycia silnych typów wyliczeniowych z odpowiednio przeładowanymi operatorami.

#include <iostream>
#include <map>

using namespace std;

enum class TrafficLight { RED , YELLOW_AFTER_RED , GREEN , YELLOW_AFTER_GREEN };

const map<underlying_type<TrafficLight>::type,string> names { {0,"red"},{1,"yellow"},{2,"green"},{3,"yellow"} };

TrafficLight operator++( TrafficLight& light )
{
    return light = static_cast<TrafficLight>((static_cast<underlying_type<TrafficLight>::type>(light)+1)%4);
}

ostream& operator <<( ostream& os , const TrafficLight& light )
{
    os << names.at(static_cast<underlying_type<TrafficLight>::type>(light));
    return os;
}

int main()
{
    TrafficLight streetLight {TrafficLight::YELLOW_AFTER_GREEN};

    while( streetLight != TrafficLight::GREEN )
    {
        cout <<  "Light color is " << streetLight << endl;
        ++streetLight;
    }

    cout << "Light color is " << streetLight << " : You can go!" << endl;

    return 0;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1