80 votes

Etendre les énumérations en C++?

Existe-t-il un moyen en C++ d'étendre/"hériter" des enumérations ?

Par exemple :

enum Enum {A,B,C};
enum EnumEx : public Enum {D,E,F};

ou au moins définir une conversion entre eux ?

2 votes

0 votes

Il y a un article très intéressant, avec du code, ici: codeproject.com/Articles/32000/…

68voto

Matthieu M. Points 101624

Non, il n'y en a pas.

enum est vraiment le pauvre élément en C++, et c'est bien sûr malheureux.

Même la enum classe introduite en C++0x ne résout pas ce problème d'extensibilité (bien qu'ils fassent certaines choses pour la sécurité des types au moins).

Le seul avantage de enum est qu'ils n'existent pas : ils offrent une certaine sécurité des types sans imposer de surcharge à l'exécution car ils sont directement substitués par le compilateur.

Si vous voulez un tel élément, vous devrez travailler vous-même :

  • créez une classe MyEnum, qui contient un int (basiquement)
  • créez des constructeurs nommés pour chacune des valeurs intéressantes

vous pouvez maintenant étendre votre classe (en ajoutant des constructeurs nommés) à volonté...

C'est une solution de contournement cependant, je n'ai jamais trouvé de moyen satisfaisant de traiter une énumération...

0 votes

Hélas, je suis d'accord. Tant de fois j'ai voulu une manière sûre de passer des indicateurs, etc. mais les enums ne sont vraiment que des ints.

0 votes

Les énumérations ne sont malheureusement pas la seule chose pauvre en C++ ...

11voto

marco Points 82

J'ai résolu de cette manière :

typedef enum
{
    #include "NetProtocols.def"
} eNetProtocols, eNP;

Bien sûr, si vous ajoutez un nouveau protocole de réseau dans le fichier NetProtocols.def, vous devez recompiler, mais au moins il est extensible.

"NetProtocols.def" contiendra uniquement les noms des champs :

HTTP,
HTTPS,
FTP

1 votes

Oui, si vous souhaitez que la définition enum soit dans une bibliothèque, vous ne pourriez pas le faire...

0 votes

@macro cela ne fonctionne pas pour moi. Pourriez-vous s'il vous plaît lister quelques contenus de NetProtocols.def

0 votes

@sree: J'ai édité la réponse

6voto

Laurence Gonsalves Points 50783

Si vous étiez capable de créer une sous-classe d'une énumération, cela devrait fonctionner dans l'autre sens.

L'ensemble des instances dans une sous-classe est un sous-ensemble des instances dans la super-classe. Pensez à l'exemple standard de "Forme". La classe Forme représente l'ensemble de toutes les formes. La classe Cercle, sa sous-classe, représente le sous-ensemble des formes qui sont des cercles.

Donc, pour être cohérent, une sous-classe d'une énumération devrait contenir un sous-ensemble des éléments de l'énumération dont elle hérite.

(Et non, C++ ne supporte pas cela.)

6 votes

C'est une interprétation très spécifique de l'héritage, qui ne s'applique pas nécessairement à toutes les utilisations de l'héritage. Je ne pense pas que cela explique vraiment pourquoi un compilateur ne pourrait pas prendre en charge enum EnumEx : public Enum {D,E,F}; de sorte qu'un EnumEx puisse être passé à une fonction attendant un Enum.

1 votes

@jon: parce que cela violerait le principe de substitution de Liskov : D serait "un" Enum (car il en hérite), mais n'aurait aucune des valeurs valides d'un Enum. Contradiction. les enums sont conçus pour être des "types énumérés" - le but est que vous définissiez le type en définissant tous les objets valides de ce type (dans le cas de C/C++, en réalité la correspondance des valeurs répertoriées à tous les types valides est un peu étrange, et implique le type utilisé pour représenter l'énumération). Il s'agit peut-être d'une interprétation très spécifique de l'héritage, mais c'est une bonne interprétation, et autant que je sache, cela informe la conception de C++.

1 votes

Comme exemple particulier où cela pourrait poser problème, supposez que je définisse un enum A {1, 65525}; et que le compilateur décide d'utiliser un entier non signé de 16 bits pour le représenter. Maintenant, supposez que je définisse enumEx : public Enum { 131071 };. Il n'y a aucun moyen pour cet objet de type EnumEx d'être passé en tant qu'instance de Enum, cela reviendrait en effet à une coupure. Oups. C'est pourquoi vous avez besoin de pointeurs en C++ pour faire de la polymorphie à l'exécution. Je suppose que C++ pourrait faire en sorte que chaque énumération ait la taille de la plus grande énumération possible. Mais conceptuellement parlant, la valeur 131071 ne devrait pas être une instance valide de Enum.

1voto

BadPirate Points 11614

http://www.codeproject.com/KB/cpp/InheritEnum.aspx passe en revue une méthode pour créer une énumération étendue.

Créez InheritEnum.h:

// -- InheritEnum.h

template 
class InheritEnum
{
public:
  InheritEnum() {}
  InheritEnum(EnumT e)
    : enum_(e)
  {}

  InheritEnum(BaseEnumT e)
    : baseEnum_(e)
  {}

  explicit InheritEnum( int val )
    : enum_(static_cast(val))
  {}

  operator EnumT() const { return enum_; }
private:
  // Note - la valeur est déclarée comme une union principalement pour aider au débogage. Si 
  // la union n'est pas souhaitée et que vous avez d'autres méthodes de débogage, modifiez-la
  // en EnumT ou en base de EnumT et faites une conversion pour le constructeur qui accepte BaseEnumT.
  union
  { 
    EnumT enum_;
    BaseEnumT baseEnum_;
  };
};

Et ensuite l'utiliser:

enum Fruit { Orange, Mango, Banana };
enum NewFruits { Apple, Pear }; 
typedef InheritEnum< NewFruit, Fruit > MyFruit;

void consume(MyFruit myfruit); 

Votre expérience peut varier.

2 votes

Une méthode très dangereuse. Si deux enums mis ensemble utilisent la même valeur, cela les confondra silencieusement.

2 votes

@dspeyer cela apporte tout de même une idée intéressante à l'ensemble du débat. votre solution est une progéniture de cela.

0 votes

Les réponses ne doivent pas être seulement des liens. (Et ce code a un comportement indéfini dans sa "conversion".)

1voto

the_drow Points 6141

Pas que je sache.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X