Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in /home/www/novacisko.cz/subdomains/bredy/init.php on line 11

Warning: mysql_connect(): Headers and client library minor version mismatch. Headers:50562 Library:100020 in /home/www/novacisko.cz/subdomains/bredy/init.php on line 11

Warning: Cannot modify header information - headers already sent by (output started at /home/www/novacisko.cz/subdomains/bredy/init.php:11) in /home/www/novacisko.cz/subdomains/bredy/index.php on line 38
Jak lépe deklarovat enumy v C++ - Bredyho blog - Ondřej Novák
Bredyho blog - Ondřej Novák

Jak lépe deklarovat enumy v C++

Jedna krátká rada, jak si neudělat v programu nepořádek


Datový typ enum snad nemusím vysvětlovat. Každý Cčkař ho zná.

V C++ můžeme použít zkrácený zápis enumu například takto:

enum Barvy {
cervena, modra, bila, zluta, cerna, oranzovat, fialova, hneda, zelena
};

Výhoda enumů je zejména ve vyšší abstrakci daného typu. Namísto používání čísel, kde by bylo definovat přiřazení, třeba 1=červená, 2=modrá, můžeme rovnou používat identifikátory.

Tuto výhodu používají i různe debuggery, které pak namísto interního číslování používají názvy identifikátorů. Při analýze programu pak přímo na obrazovce čteme například vnitřní stav nějakého výpočtu a podobně

Doporučení
Používejte enumy

Organizování Enumů

Nevýhodou enumů je zejména to, že všechny identifikátory definované v rámci enumu mají globální platnost, případně platnost v celém aktuálním namespace. Můžeme se tak snadno dostat do kolize jmen, příklad

enum StavCteni {
Ok, nelzeOtevritProCteni,nelzePrecist, jinaChyba
};

enum StavZapisu {
Ok, nelzeOtevritProZapis,nelzeZapsat, jinaChyba
};

Je zřejmé, že překladač z takové definice nebude příliš nadšen.

Zejména proto doporučuji zabalit enumy do nějakého namespace nebo do třídy. Udělá se to takto:


namespace StavCteni {
enum Enum {
Ok, nelzeOtevritProCteni,nelzePrecist, jinaChyba
};
}

namespace StavZapisu {
enum Enum {
Ok, nelzeOtevritProZapis,nelzeZapsat, jinaChyba
};
}

Používat takový enum bude kapánek ukecanější. Pro deklaraci typu musíme použít zápis StavCteni::Enum

 StavCteni::Enum loadFile(...);

Pokud chceme se stavem pracovat, musíme opět připojit jméno namespace

 if (loadFile(...) == StavCteni::Ok) {...};

Na jednu stranu se trošku víc rozepíšeme, na druhou stranu ale získáme lepší přehlednost. Ze zápisu je hned zřejmé, jaký enum se při vyhodnocení použije a snadno se odhalí případné chyby.

Umístit typ enum do separátního namespace má ještě jednu celkem významnou výhodu. Pokud potřebuje importovat enum do jiného namespace, bude to pro vás v celku noční můra

namespace NS1 {
enum Barvy {
cervena, modra, bila, zluta, cerna, oranzovat, fialova, hneda, zelena
};
class A {};
class B {};
class C {};
typedef ...
}
namespace NS2 {
//importujeme jen Barvy?
using NS1::Barvy;
}

Tohle fungovat opravdu nebude! Aby bylo možné importovat celý datový typ, je potřeba importovat každou položku enumu!

namespace NS2 {
//importujeme jen Barvy?
using NS1::Barvy;
using NS1::cervena;
using NS1::modra;
using NS1::bila;
...
...
}

Pokud však enum zabalíme do separátního namespace, budeme na tom o 1000% lépe.

namespace NS1 {
namespace Barvy {
enum Enum {
cervena, modra, bila, zluta, cerna, oranzovat, fialova, hneda, zelena
};
}
}
namespace NS2 {
//importujeme jen Barvy
namespace Barvy {
using namespace NS1::Barvy;
}
Barvy::Enum barva = Barvy::cervena;
}

Rozšiřovatelné enumy

Jako poslední ukážeme řešení pro rozšiřovatelné enumy. Jak známo, jakmile nadeklarujeme enum, nelze jej později rozšířit o nové položky. Nelze prostě enum zdědit. Toto se snad vyřeší nástupem nové verze C++.

Jestliže však opravdu takovou vlastnost potřebujeme, musíme začít enumy emulovat pomocí namespace. Ale víceméně ztratíme výhodu dekódování enumů debuggerem.

namespace Errors {
typedef int Enum;
static const Enum Ok = 0;
static const Enum generalError = 1;
static const Enum fileNotFound = 2;
static const Enum pathNotFound = 3;
static const Enum accessDenied = 5;
}
//rozšíření
namespace Errors {
static const Enum bufferIsSmall = 1001;
static const Enum invalidParameter = 1002;
static const Enum dataBlockIsNotReady = 1003;
}

Ačkoliv se tyto emulované enumy používají velice podobně, je zde vidět několik problémů

  1. Nefunguje typová kontrola, tedy porovnávat různé typy enumů (všechno to jsou inty)
  2. Musíme specifikovat mapování čísel
  3. Globálně nelze garantovat unikátní přiřazení.

I tak to může být jedno z řešení, které se občas hodí.

vytvořeno: 22.5.2009 16:51:34, změněno: 22.5.2009 16:51:34
Jsou informace v článku pro Vás užitečné?
  • (10)
  • (3)
  • (0)
  • (0)
  • (1)

Podobné články

Chcete zhubnout a nedaří se vám to? - všechno je jinak

Lidé (nejčastěji ženy) kteří "drží linii" a denně při nákupech počítají kalorie, to možná dělají zbytečně.

Tuples v C++

Pokud si pamatujete na seriál Funkce s volitelným počtem argumentů v C++, tak v této části najdete jakési pokračování, i když cílem článku je trošku něco jiného

Seznamy typů a jejich použití

Opět inspirován známým C++ guru: Andrei Alexandrescu jsem se vrhnul na implementaci seznamů typů "po svém". V této části si povíme co to je a k čemu to slouží.

Vracíme z funkce objekty - Skrytí konstruktoru

Skrývání konstruktoru může být důležité v případě, že potřebujeme v objektu použít Pimpl Idiom. Objekty totiž mohou vznikat i z datových typů, které nechceme zveřejňovat

Funkce s volitelným počtem argumentů v C++

Leckterý programátor v C jistě zná syntaxtický zápis funkce s volitelným počtem argumentů. V následujícím článku se podíváme na nevýhody tohoto nástroje a způsoby jak to implementovat jinak
Reklama: