IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

Enum, Héritage, Concaténation, Masquage


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Par défaut Enum, Héritage, Concaténation, Masquage
    En tentant de faire un GUI, je me suis rendu compte de quelques problèmes :

    Considérons la classe ci-dessous (donnée avec le GUI)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    class Button : public Objet
    {
        private :
            //Choses hérités de Objets (ne sont pas réellement présents
            std::vector<Callback> Callbacks;
            void handle_event(Evenement*evenement)
            {
                for(unsigned int i=0;i<Callbacks.size();i++)
                {
                    if(Callbacks[i].get_event()==evenement->get_event())
                        Callbacks[i](evenement);
                }
            }
            //Choses spécifiques au bouton (par exemple la police, le fond, ... ne sont pas indiqué ici
        public :
            //Les constructeurs ne sont pas présentés mais ils connectent tous ce dont il y a besoin
            enum Event{PRESSED,UNPRESSED,CLIKED, REDIM};//Ceci n'est qu'un exemple
            inline void emit(Evenement*evenement)
            {
                handle_event(evenement);
                safe_delete(evenement);
            }
            inline void connect(Function fc, int Declanch/*En réalité un Event*/)
            {
                Callbacks.push_back(Callback(fc,Declanch));
            }
     
    };
     
    class My_Button : public Button//On souhaite rajouter un type d'evenement
    {
        private :
            //Que ce qui est hérité de Button
        public :
            enum Event{PRESSED,UNPRESSED,CLIKED, REDIM, CHANGED/*Attention*/};//On utilise le masquage pour introduire de nouveaux Event
     
    };
    Pas de problème dans ce cas ci car CHANGED est bien rajouté après les autres Event de Button ; ainsi, ils interfèrerons pas.

    Cependant, dans les 2 cas ci-dessous il y a un problème :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class My_Button : public Button//On souhaite rajouter un type d'evenement
    {
        private :
            //Que ce qui est hérité de Button
        public :
            enum Event{PRESSED,CHANGED/*Attention*/,UNPRESSED,CLIKED, REDIM};//On utilise le masquage pour introduire de nouveaux Event
     
    };
     
    class My_Button : public Button//On souhaite rajouter un type d'evenement
    {
        private :
            //Que ce qui est hérité de Button
        public :
            enum Event{PRESSED, REDIM, CHANGED/*Attention*/};//On utilise le masquage pour introduire de nouveaux Event
     
    };
    Hors, je ne peux demander a mon utilisateur de connaitre tous les Event prédéfinis de ma classe Button et de les recopier puis rajouter les nouveaux.

    Ce qu'il faudrait, c'est pouvoir faire enum My_Button_Event{Button_Event,CHANGED}; auquel cas, chaque objet aurait pour Event : enum object_name(parent_object_name,Evenement propre à l'objet).

    A ma surprise un tel code compile :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <iostream>
     
    using namespace std;
     
    enum Button_Event{PRESSED,RELEASED,CLICKED,REDIM};
    enum My_Button_Event{Button_Event,CHANGED};
     
    int main()
    {
        std::cout<<PRESSED<<RELEASED<<CLICKED<<REDIM<<CHANGED<<Button_Event;//Ne devrais pas compiler avec ce dernier cout
        return 0;
    }
    Mais malheureusement affiche 012310 et non 01234 avec une erreur de compilation pour Button_Event

    Comment pallier à ce problème ?

  2. #2
    Membre Expert
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Par défaut
    Je ne suis pas sûr de bien comprendre pourquoi tu utilise des enum, mais ne serait-il pas plus simple d'utiliser des tuples ou mieux, des classes de traits pour obtenir ce comportement ?

    Sinon, avant que kohala ne tente de te recruter , sache qu'un projet de gui est actuellement lancé (bien que peu actif ces temps cis ) sur le forum.

    Peut-être pourrais-tu y contribuer/t'en inspirer ?...

  3. #3
    Membre éclairé

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Par défaut
    Le enum Event sert seulement d'identifiant pour savoir quel Fonction a connecter à quel signal (si tu relis handle_event, tu comprendras sans doute mieux...). Il me semblait qu'un enum serait parfait...

    Quant à ce projet de GUI, j'en avais pas entendu parlé. De plus, c'est le troisième post que je poste sur ce projet de GUI et je pense que si kohala avait voulu me recruté, il l'aurait déjà fait.

  4. #4
    Membre Expert
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Par défaut
    Citation Envoyé par NoIdea Voir le message
    Le enum Event sert seulement d'identifiant pour savoir quel Fonction a connecter à quel signal (si tu relis handle_event, tu comprendras sans doute mieux...). Il me semblait qu'un enum serait parfait...
    si cet enum n'est pas destiné à être modifié, oui. sinon , on risque justement d'avoir les problèmes de comportement que tu pointe. Problème que tu n'aurais pas avec des tuples.

  5. #5
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,
    Citation Envoyé par méphistopheles Voir le message
    Sinon, avant que kohala ne tente de te recruter
    KISSESSA kohala
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Tu masques tout simplement un symbole par un autre. Button_Event devient une des valeurs de My_Button_Event et n'est plus un type.
    De la même façon dans ta classe dérivée tu redéfinis de nouveau symbole avec de nouvelle valeur.

    Pour info, l'ensemble des messages windows est défini dans un .h et donc visible par tous le monde mais ce n'est peut être pas le meilleur exemple.

    wxWidgets utilise héritage de type pour différencier les différents messages plutôt que des valeurs et des enums.

    Je ne sais pas comment fonctionne Qt.

    Je pense qu'il y a moyen de faire sans des enums et des valeurs. Regardes comment font d'autres API GUI (Qt, wxWidgets par expl).

  7. #7
    Membre expérimenté
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    188
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 188
    Par défaut
    Avec Qt il me semble que c'est une énumération qui contient une plage (entre QEvent::User et QEvent::MaxUser) réservé pour les events perso. et pour créer un event perso, on utilise la fonction registerEventType() qui va retourné un entier inclus dans cette plage et qui n'as pas encore été utilisé.

  8. #8
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Tu pourrais essayer quelque chose à base de TypeList de Int2Type, et de typedef pour simplifier le nommage. Quelque chose du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    class Widget
    {
    	protected:
    		typedef LOKI_TYPELIST_2(Loki::Int2Type<0>, Loki::Int2Type<1>) ListEvent;
     
    	public:
    		typedef Loki::TL::TypeAt<ListEvent, 0>::Result Pressed;
    		typedef Loki::TL::TypeAt<ListEvent, 1>::Result Changed;
    		inline void get_event(int) {} //en réalité un Int2Type<int>::value
    };
     
    class ExtendWidget : public Widget
    {
    	protected:
    		typedef Loki::TL::Append<Widget::ListEvent, Loki::Int2Type<2> >::Result ListEvent;
     
    	public:
    		typedef Loki::TL::TypeAt<ListEvent, 2>::Result Cliked;
    };
    Ca permet un ajout simple d'event à la classe, on pourrait améliorer encore en rendant la numérotation automatique, il resterait un problème au niveau de létape de nommage, mais ca doit se résoudre via des macros.
    Il resterait la question de comment faire si l'on ne veut pas ajouter des Event mais en enlever, en rélaité la question ne se pose pas au vue du LSP.
    Le dernier point est que l'appel de la fonction est moins naturel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    ExtendWidget w;
    w.get_event(ExtendWidget::Pressed::value);

  9. #9
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    J'allais parler de tag dispatching d'ailleurs. Note que même si j'adore ce que fait Alexandrescu je préconiserais plutôt une approche à base de mpl::vector (ou mpl::list ou autre selon les accés) qui sont quand même des solutions bien plus poussées . (notamment sur les instantiations de templates)

  10. #10
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Oui, n'importe quel bibliothèque de méta-prog (du moins bibliothèque qui propose des Typelist) fera l'affaire. (j'ai utilisé Loki parce que je suis en train de finir de lire MC++D.
    A noter que dans le code que j'ai fait la Typelist sert pas à grand chose, mais je pense qu'elle devient utile si tu veus faire quelque chose de plus générique (ie s'en avoir à gérer les indice à la main). Notament récuperer le nombre d'event en utilisant la longueur de la liste et vérifier si un event existe bel et bien.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Héritage de enum
    Par oliveettom dans le forum Général Java
    Réponses: 12
    Dernier message: 25/04/2013, 17h14
  2. Enum, question héritage!
    Par remip dans le forum Langage
    Réponses: 7
    Dernier message: 23/03/2010, 18h46
  3. ADO .NET data services, EF et masquage de type enum
    Par chrisdot dans le forum Silverlight
    Réponses: 0
    Dernier message: 20/10/2009, 18h24
  4. [Enum] Héritage entre enum
    Par Invité dans le forum Langage
    Réponses: 4
    Dernier message: 31/01/2008, 09h01
  5. Héritage d'interface avec masquage de méthode
    Par Pongten dans le forum ASP.NET
    Réponses: 4
    Dernier message: 05/09/2007, 22h16

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo