Dans l'extrait de code suivant, l'énumération Color
est déclarée dans la classe Car
afin de limiter la portée de l'énum et d'éviter de "polluer" l'espace de noms global.
class Car
{
public:
enum Color
{
RED,
BLUE,
WHITE
};
void SetColor( Car::Color color )
{
_color = color;
}
Car::Color GetColor() const
{
return _color;
}
private:
Car::Color _color;
};
(1) Est-ce un bon moyen de limiter la portée de l'énum Color
? Ou devrais-je le déclarer en dehors de la classe Car
, mais éventuellement dans son propre espace de noms ou structure? Je viens de tomber sur cet article aujourd'hui, qui défend ce dernier et discute de quelques points de Nice concernant les enums: http://gamesfromwithin.com/stupid-c-tricks-2-better-enums .
(2) Dans cet exemple, lorsque vous travaillez dans la classe, vaut-il mieux coder l'énum en tant que Car::Color
, ou serait simplement Color
suffire? (Je suppose que le premier est meilleur, juste au cas où il y aurait une autre Color
énum déclarée dans l'espace de noms global. Ainsi, au moins, nous sommes explicites à propos de l'énum auquel nous faisons référence.)
Si Color
est quelque chose qui est spécifique à Car
s, alors vous limitez sa portée. Si vous avez une autre énumération Color
que d’autres classes utilisent, vous pouvez également la rendre globale (ou du moins en dehors de Car
).
Ça ne fait aucune différence. S'il y en a un global, le local est toujours utilisé car il est plus proche de la portée actuelle. Notez que si vous définissez ces fonctions en dehors de la définition de classe, vous devrez spécifier explicitement Car::Color
dans l'interface de la fonction.
De nos jours - en utilisant C++ 11 - vous pouvez utiliser enum class pour cela:
enum class Color { RED, BLUE, WHITE };
AFAII cela fait exactement ce que vous voulez.
Je préfère l'approche suivante (code ci-dessous). Il résout le problème de "pollution de l'espace de noms", mais il est également beaucoup plus typé (vous ne pouvez pas affecter et même comparer deux énumérations différentes, ou votre énumération avec d'autres types intégrés, etc.).
struct Color
{
enum Type
{
Red, Green, Black
};
Type t_;
Color(Type t) : t_(t) {}
operator Type () const {return t_;}
private:
//prevent automatic conversion for any other built-in types such as bool, int, etc
template<typename T>
operator T () const;
};
Usage:
Color c = Color::Red;
switch(c)
{
case Color::Red:
//некоторый код
break;
}
Color2 c2 = Color2::Green;
c2 = c; //error
c2 = 3; //error
if (c2 == Color::Red ) {} //error
If (c2) {} error
Je crée une macro pour faciliter l'utilisation:
#define DEFINE_SIMPLE_ENUM(EnumName, seq) \
struct EnumName {\
enum type \
{ \
BOOST_PP_SEQ_FOR_EACH_I(DEFINE_SIMPLE_ENUM_VAL, EnumName, seq)\
}; \
type v; \
EnumName(type v) : v(v) {} \
operator type() const {return v;} \
private: \
template<typename T> \
operator T () const;};\
#define DEFINE_SIMPLE_ENUM_VAL(r, data, i, record) \
BOOST_PP_Tuple_ELEM(2, 0, record) = BOOST_PP_Tuple_ELEM(2, 1, record),
Usage:
DEFINE_SIMPLE_ENUM(Color,
((Red, 1))
((Green, 3))
)
Quelques références:
En général, je mets toujours mes enums dans un struct
. J'ai vu plusieurs directives, y compris "préfixer".
enum Color
{
Clr_Red,
Clr_Yellow,
Clr_Blue,
};
J'ai toujours pensé que cela ressemblait davantage à C
directives qu'à C++
(pour l'une en raison de l'abréviation et également en raison des espaces de noms dans C++
).
Donc, pour limiter la portée, nous avons maintenant deux alternatives:
Personnellement, j’ai tendance à utiliser un struct
parce qu’il peut être utilisé comme paramètre pour la programmation de modèles alors qu’un espace de noms ne peut pas être manipulé.
Les exemples de manipulation incluent:
template <class T>
size_t number() { /**/ }
qui retourne le nombre d'éléments d'enum à l'intérieur de la struct T
:)
Si vous créez une bibliothèque de code, j'utiliserais un espace de noms. Cependant, vous ne pouvez toujours avoir qu'une seule couleur enum dans cet espace de noms. Si vous avez besoin d'une énumération qui peut utiliser un nom commun, mais qui peut avoir différentes constantes pour différentes classes, utilisez votre approche.