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 :

Equivalent en C++ classes internes anonymes en Java


Sujet :

C++

  1. #1
    Membre à l'essai
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2008
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 9
    Points : 17
    Points
    17
    Par défaut Equivalent en C++ classes internes anonymes en Java
    Bonsoir,
    je suis actuellement sur un projet d'outils ecrits en C++ pour la librairie SDL.
    Ces outils permettent de créer et de manipuler un moteur de jeu, une banque de son, des fichiersde ressources et de configurations, pour faciliter la création d'un jeu vidéo en 2D. Une boîte à (GUI)widget est également incluse. Mon problème survient dans l'interaction entre l'utilisateur et les widgets. L'organisation des classes est la suivante:

    - Classe Abstraite Widget.
    |-> Menu (hérite de Widget)
    |-> DialogBox (hérite de Widget)
    |-> etc...

    Chaque Widget dispose d'un certain nombre de WidgetItem.

    - Classe Abstraite WidgetItem
    |-> TextLabel (hérite de WidgetItem)
    |-> ImageLabel (hérite de WidgetItem)
    |-> etc...

    C'est en interagissant (par double clique) sur les WidgetItem que l'on déclenche des actions. Chaque widget doit être capable de réaliser une action spécifique et dispose donc d'une méthode "action()" virtuelle pure qu'il faut définir dans une classe fille. Il est fastidieux d'écrire une nouvelle classe héritant de TextLabel (ou autre classe héritant de WidgetItem) pour définir l'action spécifique à réaliser.
    Ma question est donc la suivante: existe t-il un mécanisme proche de celui du Java en C++ pour créer des classes internes anonymes.

    Exemple en Java:
    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
    38
    39
    40
    public interface Action {
    void do_something();
    }
    ...
    public class TextLabel {
        private Action action;
     
        public void add_action(Action a) {
            action = a;
        }
     
        public void action() {
            a.do_something();
        }
    }
    ...
    public class Menu {
         private int a;
         private TextLabel label;
     
         public Menu() {
             label = new TextLabel();
             label.add_action( new Action() {
                                         void do_something() {
                                              // implémentation de l'interface
                                              // la classe interne a accès aux éléments de Menu
                                              a++;
                                         }
             });
             label.action()         // augmente le membre "a" de 1
             label.add_action( new Action() {
                                         void do_something() {
                                              // implémentation de l'interface
                                              // la classe interne a accès aux éléments de Menu
                                              a--;
                                         }
             });
             label.action()         // reduit le membre "a" de 1
        }
    }
    La seule solution que j'ai trouvé pour l'instant est de déclarer comme attribut dans la classe WidgetItem un pointeur de fonction.

    On obtient alors en C++:
    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
    class WidgetItem {
        public:
            ...
            void set_action(void (*f)(void)) {
                function = f;
            }
     
            void action() {
                function();
            }
     
            private:
                void (*function)(void);
    };
    ...
    void do_something() {
        printf("Action");
    }
    ...
    void do_something_else() {
        printf("Another Action");
    }
     ...
    // dans le main
    WidgetItem i();
    i.set_action(do_something);
    i.action();        // Affiche sur le terminal  "Action"
    i.set_action(do_something_else);
    i.action();       // Affiche sur le terminal "Another Action"
    Cette méthode arrive vite à ses limites lorsque l'action à réaliser doit avoir accès aux membres d'autres objets..

    Je suis à l'écoute de toutes vos solutions aussi "bidoullage" soient-elles .
    Merci d'avance !

  2. #2
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Mais c'est là qu'il y a erreur de "conception"...
    C'est pas le widget qui doit réagir au click... mais un objet qui doit réagir au click sur le widget.... (ce qui, au passage, te simpliefiera grandement la vie quand tu devras "rejouer" quelque chose sans widget).

    La dernière fois que j'avais joué avec un framework (mais ca remonte à un paquet d'années... genre 12/13) de GUI, on était arrivé à la conclusion suivante (qui, étonnemment ou non, est la manière dont la plupart des OS fonctionnent).
    Quand un widget(item) doit générer un evenement, il genere cet evenement... genre "user clicked on me"...
    Ensuite cet evenement "remonte" la liste des widgets jusqu'à disparaitre si personne ne se sert de l'évenement.

    La classe widget de base a donc un pointeur sur le widget parent (pour redispatcher le message), et surtout:
    - Une map<eventid,vector<listener*>>

    Quand un event est dispatché par le wiget:
    1. Il regarde si il existe une liste de listener associé par à cet event.
    2. Pour chaque listener dans cette liste il appelle une fonction "handleEvent(event)" jusqu'à que l'un de ces listener lui dise: "STOP, je catch le truc".
    3. Si aucun listener n'a "catché" l'évenement, alors il appele le "handleEvent" de son parent (et oui, un widget est un listener), qui, par défaut, va dispatcher l'event à son tour.

    Windows rajoute des fioritures, par exemple: est ce que l'evenement doit remonter au parent... (peut être interessant pour gérer un ascenseur qui est un widget avec 5 sous widgets et qui doit piloter le widget parent )

    Un truc genre (pseudocode):
    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
     
    interface EventListener
    {
         virtual bool handleEvent(const Event& evt) = 0;
    };
     
    class Widget : public EventListener
    {
        Widget* pParent;
        bool bBroadcastToParent;
        Map<int,Vector<EventListener*>>  listeners;
     
        public:
           virtual bool handleEvent(const Event& evt) {
               bool catched = dispathEvent(evt);
               if (!catched && bBroadcastToParent && pParent) 
                            catched = pParent->handleEvent() :
               return catched;
           }
     
       protected:
           virtual bool dispatchEvent(const Event& evt) {
                 ...
            }
    };
    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

  3. #3
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Pour définir ce genre de chose en C++, on utilisera généralement des foncteurs (voire boost::function et boost::bind, par exemple), mieux encore, on les mettra avec un système de signaux/slots (il y a un truc comme ça dans Qt par exemple, et boost::signal en fourni une version portable).

    Dans le futur, le C++ fournira des fonction lambda pour aider (entre autre) à définir le contenu des slots.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  4. #4
    Membre à l'essai
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2008
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 9
    Points : 17
    Points
    17
    Par défaut

    Je vais pousser mon analyse dans ces voies là. La 1ere solution des écouteurs est adoptée dans SWING pour Java. Un petit coup d'oeil à la Javadoc et on adapte ça en C++. C'est peut être aussi l'occasion de se lancer dans l'apprentissage de Boost, le systeme de signal&slot à la Qt est assez intéressant.

    Nicroman une question: pour chaque widget de l'ensemble du programme faut-il définir un event_id? N'y-a-t-il pas de méthode plus générique car à chaque ajout de widget, il faut définir une nouvelle constante ? (Dans un jeu typiquement RPG, il y a un nombre considérable de menus, tableaux, boutons et etc). Merci !

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

Discussions similaires

  1. classe interne anonyme
    Par oliveettom dans le forum Langage
    Réponses: 1
    Dernier message: 09/05/2013, 00h25
  2. Redéfinir un constructeur dans une classe interne anonyme
    Par pigpen dans le forum Débuter avec Java
    Réponses: 3
    Dernier message: 31/10/2011, 13h36
  3. Réponses: 5
    Dernier message: 19/07/2009, 19h20
  4. Réponses: 3
    Dernier message: 09/04/2008, 11h24
  5. Classe anonyme et classe interne
    Par amazircool dans le forum Langage
    Réponses: 8
    Dernier message: 26/12/2007, 14h45

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