Eddig többnyire számokkal és stringekkel foglalkoztunk. A valós világ modellezéséhez előfordulhat, hogy egy változónak csak korlátozott számú értéket szeretnénk megengedni. Lehet, hogy szeretnél egy saját típust, amelynek csak néhány, különböző nevű értéke lehet. Gondolj például egy gördeszkagyárra, ahol a deszka anyaga csak juhar, bambusz vagy műanyag lehet.
Ezeket az értékeket kódolhatnád egész számokkal is, de plusz kódot kellene írnod annak ellenőrzésére, hogy nem érkezik-e érvénytelen érték a rendszerből az anyagra.
Az ilyen varázsszámok jelentését nehéz követni a forráskódban, és könnyen összekeverednek.
Az enumerations segítségével kifejezőbb kódot írhatsz, és elkerülheted a nem szándékos összehasonlítási hibákat.
Az ilyen fajta felsorolás pontos neve scoped enumeration.
Az alábbi részlet megmutatja, hogyan definiáljunk egy DeckMaterial enumeration-t.
Figyeld meg az enum class kulcsszót, és a definíció végén lévő ;-t:
enum class DeckMaterial {
maple,
bamboo,
plastic
};
Most nézd meg az árazó függvényt a gördeszkaboltban, és figyeld meg a scope resolution operátort (::), amellyel megadod, hogy egy enumerator melyik enumeration-höz tartozik:
double deck_price(double base_price, DeckMaterial material) {
if(material == DeckMaterial::plastic) {
return base_price * 0.9;
}
return base_price * 1.3;
}
Képzeld el, hogy van egy második enumeration-öd a kerék anyagához:
enum class WheelMaterial {
steel,
clay,
plastic
};
Bár a kerekek és a deszka anyaga is plastic lehet, a kettő mégsem keverhető össze.
Két különböző típusról van szó: a DeckMaterial plastic és a WheelMaterial plastic.
Minden enumeration a saját scope-jában tartja a saját enumerators-eit, a saját namespace-ében.
Ezért is hívják őket scoped enumerations-nek.
Talán arra gondolsz, hogy ha van scoped, akkor biztos vannak unscoped felsorolások is, és ebben igazad van.
Az Unscoped enumerations egyre kevésbé népszerűek, mert mind ugyanazt a globális névteret használják.
Az osztozás miatt nem lehet két unscoped enumerations, amelyeknek ugyanazok lennének az enumerators-ei, mint például a plastic a fenti példában.
Ráadásul az unscoped enumerations implicit módon egész számokká alakulnak.
Az alábbi példa meglepő eredményt mutat:
enum CitrusFruits {
lemons, // 0
oranges, //1
};
enum IceCream {
walnut, // 0
apples, // 1
};
bool comparison{apples == oranges};
// => true
// Example from above:
bool comparison{DeckMaterial::plastic == WheelMaterial::plastic};
// => Does not compile!
Ha scoped enumerations-t szeretnél egész számmá alakítani, használhatod a static_cast<int>-et.
A többi nyelvhez hasonlóan a C++ is biztosít switch utasítást.
A switch utasításokkal rövidebben írhatod le a hosszú if ... else if utasításokat.
Egy switch létrehozásához a switch kulcsszóval kezdjük, amelyet egy egész szám követ.
Ezután a case kulcsszóval deklaráljuk az egyes feltételeket.
Deklarálhatunk egy default esetet is, amely akkor fut le, ha az előző case feltételek egyike sem teljesült.
Minden esetet break (vagy return) utasítással kell lezárni.
int price{0};
int adults{3};
int kids{2};
switch (int group_size{adults + kids}) {
case 1:
price = 50;
break;
case 2:
price = 70;
break;
default:
price = group_size * 30;
}
A switch szerkezet egyik fontos tulajdonsága, hogy a kód addig folytatja a végrehajtást, amíg egy break (vagy return) utasítás meg nem állítja.
Ez váratlan viselkedéshez vezethet.
int adults{1};
int kids{0};
switch (int group_size{adults + kids}) {
case 1:
price = 50;
case 2:
price = 70;
default:
price = group_size * 30;
}
// price will be 30!
A folytatólagos végrehajtás fő felhasználási esete az, amikor egy utasításhoz több címke tartozik. Több switch-eredmény is ugyanahhoz a végrehajtandó kódrészhez vezethet. Így például egy foglalási alkalmazásban a 2-es és 3-as csoportméretnél ugyanaz a függvény hívható:
switch (group_size) {
case 1:
book_room();
break;
case 2:
case 3:
book_apartment(group_size);
break;
default:
book_house(group_size);
}
// book_apartment happens when group_size is 2 or 3
A barátod, Helma készített egy kis online játékot, amely gyorsan népszerűvé vált. A neve HellMath. A kis közösség odavonzott néhány trollt, akik meglehetősen kellemetlenné teszik a játékot és a fórumokat. Helma megkért, hogy dolgozz egy új jogosultsági rendszeren a bajkeverők elkülönítésére.
A fórum három különböző műveletet támogat:
Négyféle fióktípus létezik, mindegyikhez más alapértelmezett jogosultságok tartoznak:
Helma rájött, hogy semmi értelme kitiltani a trollfiókokat. A stratégiája az, hogy azt a látszatot kelti bennük, hogy az idejük „jól van befektetve”, a bejegyzéseiket viszont csak a többi troll látja. Ahol prioritási sorrendre van szükség, ott a trollok minden sorozatban az utolsók. Amikor bekapcsolódnak egy játékba, a rendelkezésre álló játékosok köre is a többi trollra korlátozódik.
Ezt a gyakorlatot shadow-banning néven emlegetik.
Először definiálj egy AccountStatus felsorolást, amely a négy fióktípust képviseli: troll, guest, user és mod.
Ezután definiálj egy Action felsorolást a három jogosultságtípus képviseletére: read, write és remove.
A fórum minden bejegyzése eltárolja a bejegyző AccountStatus-át a metaadataiban.
Gondoskodj róla, hogy a trollok bejegyzéseit csak a többi troll lássa.
Helmának szüksége van egy display_post függvényre, amely két AccountStatus típusú argumentumot kap, és egy bool értékkel tér vissza.
Az első argumentum a bejegyző státusza, a második a megtekintő státusza.
using namespace hellmath;
display_post(AccountStatus::troll, AccountStatus::user);
// => false
display_post(AccountStatus::mod, AccountStatus::guest);
// => true
Helmának kell egy mód arra, hogy ellenőrizze, engedélyezett-e egy adott művelet egy felhasználónak.
Kérlek, valósítsd meg a permission_check függvényt, amely első argumentumként egy Action értéket kap, másodikként pedig egy AccountStatus-ot, amivel össze kell vetni.
A függvény egy bool értékkel térjen vissza a bevezetőben felsorolt jogosultságoknak megfelelően.
permission_check(Action::remove, AccountStatus::guest);
// => false
permission_check(Action::write, AccountStatus::mod);
// => true
Hogy a játékban lévő valódi játékosokat felelősségre lehessen vonni a tetteikért, a Hellmath megtagadja a hozzáférést a vendégfelhasználóktól. Ahogy fentebb is szó volt róla, Helma azt szeretné, ha a trollok egymást trollkodnák. A többi felhasználó közötti játékbeli kapcsolódás korlátozás nélküli.
Valósítsd meg a valid_player_combination függvényt, amely ellenőrzi, hogy két játékos csatlakozhat-e ugyanahhoz a játékhoz.
A függvény két AccountStatus típusú paramétert kap, és egy bool értékkel tér vissza.
valid_player_combination(AccountStatus::guest, AccountStatus::mod);
// => false
valid_player_combination(AccountStatus::troll, AccountStatus::troll);
// => true
Mivel a játék és a fórumok hatalmasat nőttek, Helmának most a felhasználók között kell elosztania a számítási kapacitást és a sávszélességet. A vészhelyzetek kezelésére a moderátorok kapják a legmagasabb prioritást. A vendégek a normál felhasználók mögé kerülnek a sorban, a trollok pedig mindenki más mögé.
Valósítsd meg a has_priority függvényt, amely két AccountStatus argumentumot kap, és akkor és csak akkor ad vissza true értéket, ha az első fiók szigorúan magasabb prioritású, mint a második.
has_priority(AccountStatus::guest, AccountStatus::mod);
// => false
has_priority(AccountStatus::user, AccountStatus::troll);
// => true
Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) C++ nyelvet 19 fogalom100 feladat segítségével, valódi emberi mentorálással, mindez ingyen.