août
2008
Les énumérations peuvent être source de problèmes de pollution de portée, comment les résoudres ?
Un rappel sur les énumérations
Les énumérations sont un outil très puissant puisqu’elle permettent de définir des types n’acceptant que certaines valeurs bien précises.
Exemple
va définir un type Carte ne pouvant prendre que les valeurs Pique,Coeur,Carreau ou encore Trefle.
Il est aussi possible de définir une énumération anonyme. Dans ce cas, les valeurs dans l’énumération sont tout simplement des constantes.
Exemple:
enum {alpha,beta,release};
va définir 3 constantes : alpha, beta et release.
Mais dans tous les cas, les valeurs définies seront dans le namespace global. Autrement dit,si on souhaite avoir une constante de même nom dans deux énumérations différentes, ce n’est pas possible.
Exemple:
enum Couleur {Couleur, Orange}; //ne compilera pas, Orange est deja defini.
Ce n’est pas très pratique, avouons le. Comment peut-on remédier à cela ?
Limiter la portée des énumérations globales
Comme nous l’avons vu, une énumération définie le namespace globale va le polluer entiérement. Ce que propose le C++ pour éviter les conflits de nom est de pouvoir créer son propre namespace. le namespace (ou est espace de nom en français), est un mécanisme permettant de regrouper dans une même portée un ensemble de classes, fonctions ou encore d’objets ayant des relations en communs. Le namespace le plus connu est std: il représente le namespace de la bibliothèque standard.
Donc pour résoudre notre problème de conflit de nom, il suffit de définir notre énumération dans un namespace personnel. On appel souvent ce namespace de la même façon que l’énumération de façon à pouvoir écrire des choses comme:
Carte::Type c= Carte::Pique;
avec la définition de l’énumération sous la forme:
{
enum Type {Pique,Trefle,Coeur,Carreau};
}
Limiter la portée des énumérations locales à une classe
Cette solution est adaptée aux énumérations globales, mais que se passe t’il pour les énumérations locales à une classe ?
En effet, en C++ on peut définir une énumération dans une classe.
Exemple:
class FruitColore
{
enum Fruit {Pomme, Orange};
enum Couleur {Vert,Orange};
};
Mais cette classe ne compilera pas, à cause de la redéfinition d’orange. et on ne peut pas passer par un namespace, puisque un namespace dans une classe n’aurait pas beaucoup de sens.
La solution est de passer par les structures. En definissant l’énumération dans une structure, on limite sa portée à la dite structure.
Exemple:
{
struct Fruit {enum {Pomme, Orange};};
struct Couleur {enum {Vert,Orange};};
};
Pour créer des types et non juste définir des constantes, il suffit de rajouter un nom à l’énumération.
Exemple:
{
struct Fruit {enum type {Pomme, Orange};};
struct Couleur {enum type {Vert,Orange};};
};
void foo(FruitColore::Fruit::type t)
{
std::cout<<"t= "<<t<<std::endl;
}
Conclusion
L’utilisation des namespace et de structure pour limiter la portée des énumérations est quelque chose de bien pratique sur plusieurs points, mais amené à disparaitre à cause des class enum de C++0x, qui feront ce que nous avons fait (et même plus) de façon bien plus rapide.
sympa