Enums polymorphes

Enums polymorphes?

En C ++, nous utilisons souvent le polymorphism pour permettre à un ancien code de gérer du nouveau code – par exemple, tant que nous sous-classons l’interface attendue par une fonction, nous pouvons passer la nouvelle classe et attendre qu’elle fonctionne correctement avec le code qui a été utilisé. écrit avant la nouvelle classe a jamais existé. Malheureusement, avec les enums, vous ne pouvez pas vraiment faire cela, même si vous le souhaitez parfois. (Par exemple, si vous gérez les parameters de votre programme et que vous les stockiez tous en tant que valeurs enum, il serait peut-être intéressant de disposer d’une enum, settings_t, de laquelle tous vos autres enum hérités, de manière à pouvoir stocker chaque nouvelle enum dans la liste des parameters. Notez que, comme la liste contient des valeurs de types différents, vous ne pouvez pas utiliser de modèles .)

Si vous avez besoin de ce type de comportement, vous êtes obligé de stocker les énumérations sous forme d’entiers, puis de les récupérer à l’aide de typecasts pour atsortingbuer la valeur particulière au paramètre qui vous intéresse. Et vous ne profiterez même pas de dynamic_cast pour vous aider à garantir la sécurité de la diffusion. Vous devrez vous fier au fait que des valeurs incorrectes ne peuvent pas être stockées dans la liste.

Je cite un tutoriel de programmation C ++ .

Quelqu’un peut-il s’il vous plaît expliquer plus en profondeur et avec quelques exemples comment fonctionne Enums polymorphes? Et dans le cas où j’ai des modèles?

En termes simples, une enum est simplement une valeur constante nommée, par exemple:

 enum Settings { setting_number_0, setting_number_1, setting_number_2, }; 

Dans l’exemple ci-dessus, setting_number_X est simplement une constante nommée pour la valeur X , car les valeurs d’énumération commencent à 0 et augmentent de façon monotone.

Conserver ces éléments dans un type de conteneur donne un type de base d’entiers de stockage, mais peut néanmoins être quelque peu dactylographique.

 std::vector app_settings; // this works app_settings.push_back(setting_number_0); // this is a comstack time failure, even though the underlying storage // type for Setting is an integral value. This keeps you from adding // invalid settings types to your container (like 13 here) app_settings.push_back(13); // but you also cannot (directly) add valid setting values (like 1) // as an integral, this is also a comstack time failure. app_settings.push_back(1); 

Supposons maintenant que vous souhaitiez append des types de parameters spécifiques supplémentaires et les conserver tous dans un conteneur.

 enum DisplaySettings { // ... }; enum EngineSettings { // ... }; 

Désormais, si vous souhaitez conserver tous les parameters dans un même conteneur, vous ne pouvez pas en toute sécurité . Vous pouvez stocker toutes les valeurs intégrales dans un conteneur de std::vector ou similaire, mais le problème est que vous ne pouvez pas déterminer les types intégraux qui appartiennent à quelles énumérations de parameters. De plus, étant donné que les types sont différents, vous ne pouvez pas les stocker dans un seul conteneur de type sécurisé.

La bonne façon de procéder consiste à stocker la fonctionnalité du paramètre dans le conteneur, quelque chose comme ceci:

 #include  #include  // This is our "base class" type so we can store lots of // different setting types in our container class setting_action { public: // we enable the setting by calling our function void enable_setting() { setting_function_(this); } protected: // This is a function pointer, and we're using it to get some // comstack time polymorphism typedef void (*setting_function_type)(setting_action* setting); // these can only be constructed by derived types, and the derived // type will provide the polymorhpic behavior by means of the // above function pointer and based on the derived type's handler setting_action(setting_function_type func) : setting_function_(func) { } public: ~setting_action() { } private: setting_function_type setting_function_; }; // This is the derived type, and where most of the magic // happens. This is templated on our actual setting type // that we define below template  class templated_setting_action : public setting_action { public: templated_setting_action(Setting setting) : setting_action(&templated_setting_action::enable_setting) , setting_(setting) { } // This function catches the "enable_setting" call from // our base class, and directs it to the handler functor // object that we've defined static void enable_setting(setting_action* base) { templated_setting_action* local_this = static_cast*>(base); local_this->setting_(); } private: Setting setting_; }; // this is just a shorthand way of creating the specialized types template  setting_action* create_specialized_setting_action(T type) { return new templated_setting_action(type); } // Our actual settings: // this one displays the user name struct display_user_name { void operator()() { std::cout << "Chad.\n"; } }; // this one displays a short welcome message struct display_welcome_message { void operator()() { std::cout << "Ahh, the magic of templates. Welcome!\n"; } }; // now, we can have one container for ALL our application settings std::vector app_settings; int main() { // now we can add our settings to the container... app_settings.push_back(create_specialized_setting_action(display_user_name())); app_settings.push_back(create_specialized_setting_action(display_welcome_message())); // and individually enable them app_settings[0]->enable_setting(); app_settings[1]->enable_setting(); // also, need to delete each setting to avoid leaking the memory // left as an exercise for the reader :) return 0; }