Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème d'Amitié

je suis perdu...

    12 septembre 2011 à 22:48:29

    Bonjours à tous, je re-poste, puisque mon ancien topique a été verrouiller.

    Citation : moi même


    J'ai une classe abstraite Action, cette classe est obligée d'être hérité pour être utiliser. J'ai une autres classe Perso qui a des attributs private.

    Ce que je voudrai faire, c'est que tout les dérivée de Action peuvent accéder au attribut private de la class Perso. j'ai un peut de mal avec l'amitié et je ne comprend pas qui doit être amis avec qui la dedans...

    Merci d'avance ;)



    Voici mon ancien, massage. Je sais faire amis:
    une fonction avec une classe,
    une classe avec une classe,
    mais pas tout une famille avec une classe, et c'est la mon problème ^^

    Merci d'avance :)
    • Partager sur Facebook
    • Partager sur Twitter
      12 septembre 2011 à 22:58:44

      L'amitié ne s'hérite pas (tu as posté la question sur le forum il y a peu).
      Une solution à la volée : sépare tout ce qui relève de la donnée à l'intérieur de Personnage dans une classe Data_Perso et envoie ça à ta fonction virtuelle.
      Code explicatif (non testé) :
      struct Data_Perso
      {
          //des données
      };
      
      class Action
      {
          public :
              virtual ~Action() = 0;
              void doAction(Data_Perso& data) const {do_action(data);} //Edit : do est un mot-clé
      
          private :
              virtual void do_action(DataPerso&) const {}
              
      };
      
      class Perso
      {
          public :
              void apply(const Action& action) {action.doAction(_data);}
              //Le reste de l'interface
          private :
              Data_Perso _data;
      };
      
      • Partager sur Facebook
      • Partager sur Twitter
        12 septembre 2011 à 23:13:58

        je pense avoir compris.
        On appelle une fonction de Perso, cette fonction qui peut accéder a ses données private, appelle la fonction de l'Action avec en paramètre ses données. Je vais faire des modification, et je reviens s'il y a un problème :-°
        • Partager sur Facebook
        • Partager sur Twitter
          13 septembre 2011 à 0:35:32

          Fait en sorte que le perso offre aux actions les moyens de chercher à altérer l'état du perso.
          Libre au perso de refuser (ce n'est pas à l'action de chercher à vérifier si le perso a des immunités temporaires ou permanentes).

          http://www.siteduzero.com/forum-83-301 [...] html#r2792537
          • Partager sur Facebook
          • Partager sur Twitter
          C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
            13 septembre 2011 à 20:53:46

            je ne comprend pas trop le lien que tu m'as donné...
            Mais j'ai eu une autre idée.
            Le classe Action a en attribut privée un pointeur sur Data_Perso.
            Et une méthode
            Stats Perso::upDateAction(Action&)
            Elle remet a jour ce pointeur pour qu'il pointe sur les données du perso (j'utilise l'amitié, mais dans l'autre sens pour qu'il accède au attribut private)

            Mon code (Stats ce sont les données du perso, et combat est un autre classe ^^ )

            #ifndef ACTION_H
            #define ACTION_H
            
            struct Combat;
            struct Stats;
            #include "Perso.h"
            
            struct Action
            {
                Action(Perso* perso) : m_perso(perso)
                    {perso->upDateAction(*this);}
            
                Perso* m_perso;
            
                virtual void executer(Combat*) = 0;
                virtual ~Action(){};
            
                friend void Perso::upDateAction(Action&);
            
                protected: Stats* m_stats;
            };
            
            #endif
            


            #ifndef COMBAT_H
            #define COMBAT_H
            
            #include "ListeDAction.h"
            #include "Perso.h"
            #include <map>
            #include <SFML/Graphics.hpp>
            
            struct Combat : std::map<std::string, Perso*>
            {
                ListeDAction m_liste1;
                ListeDAction m_liste2;
            
                void action();
            
                sf::IntRect m_limite;
            
                void afficherCarte(sf::RenderWindow &app);
            };
            
            #endif
            


            #include "Perso.h"
            #include "Action.h"
            
            Perso::Perso(std::string nom, bool allie, int x, int y, direction direction) :
                    m_stats(nom, allie, x, y, direction){}
            
            void Perso::upDateAction(Action& action)
            {
                action.m_stats = &m_stats;
            }
            
            bool Perso::getAllie(){return m_stats.m_allie;}
            int Perso::getX(){return m_stats.m_x;}
            int Perso::getY(){return m_stats.m_y;}
            direction Perso::getDirection(){return m_stats.m_direction;}
            std::string Perso::getNom(){return m_stats.m_nom;}
            int Perso::getHP_Max(){return m_stats.m_HP_Max;}
            int Perso::getPA_Max(){return m_stats.m_PA_Max;}
            int Perso::getHP(){return m_stats.m_HP;}
            int Perso::getPA(){return m_stats.m_PA;}
            int Perso::getTE(){return m_stats.m_TE;}
            int Perso::getForce(){return m_stats.m_force;}
            int Perso::getMagie(){return m_stats.m_magie;}
            int Perso::getDefense(){return m_stats.m_defense;}
            int Perso::getEsprit(){return m_stats.m_esprit;}
            int Perso::getAgilite(){return m_stats.m_agilite;}
            int Perso::getEndurence(){return m_stats.m_endurence;}
            int Perso::getMaitrise(){return m_stats.m_maitrise;}
            

            • Partager sur Facebook
            • Partager sur Twitter
              13 septembre 2011 à 21:34:27

              C'est un lien avec exemple de comment s'y prendre sans amitité
              • Partager sur Facebook
              • Partager sur Twitter
              C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                14 septembre 2011 à 19:00:23

                Ca veut dire quoi quand le nom du='une classe est composé d'un '::'
                Par exemple
                struct Action::Generique{...}
                • Partager sur Facebook
                • Partager sur Twitter
                  14 septembre 2011 à 19:24:14

                  C'est juste des portées qui s'enchainent.
                  Action peut-être un espace de noms, ou une classe/struct. Cela revient au même. Chacune des deux approches a des avantages différents en matière de méta-prog, d'amis, etc. Mais ici je ne les exploite pas. Mon but est juste de donner des noms sympas: une action générique, une action de soin, une action d'attaque, etc.
                  (considère qu'Action est un espace de noms)
                  • Partager sur Facebook
                  • Partager sur Twitter
                  C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                    14 septembre 2011 à 19:40:31

                    Ok, mais je ne comprend toujours ton code dans le lien que tu m'as donné... c'est quoi l'idée en gros?
                    • Partager sur Facebook
                    • Partager sur Twitter
                      15 septembre 2011 à 0:18:39

                      Les bestioles choisissent les actions qu'elles veulent réaliser. Si elles y arrivent, ces actions produisent des effets sur des cibles.
                      Pour cela, les cibles peuvent subir certaines altérations (prévues) à l'avance, et c'est ce que font les effets : ils cherchent à altérer des cibles (ce sont elles au final qui déterminent comment l'altération est réalisée précisément).

                      Et il n'y a pas d'amis, ni de viol de la Loi de Déméter, etc.
                      • Partager sur Facebook
                      • Partager sur Twitter
                      C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                        15 septembre 2011 à 18:41:39

                        Oui, mais comment les effet accède à la partie private de la cible (je conprend toujours pas)

                        Je vais comme même mettre mon code

                        ...

                        Donnes_Perso.h
                        Une classe simple, avec implémentation du constructeur (seul méthode) directement dans le header.
                        Ce sont les donnés "privées" du perso
                        #ifndef STATS_H
                        #define STATS_H
                        
                        #include <string>
                        
                        enum direction{HAUT,BAS,GAUCHE,DROITE};
                        
                        struct Donnes_Perso
                        {
                            Donnes_Perso(std::string nom = "", bool allie = false, int x = 0, int y = 0, direction direction = HAUT) :
                                m_allie(allie),
                                m_x(x), m_y(y),
                                m_direction(direction),
                                m_nom(nom),
                                m_HP_Max(0), m_PA_Max(0),
                                m_HP(0), m_PA(0), m_TE(0),
                                m_force(0), m_magie(0),
                                m_defense(0), m_esprit(0),
                                m_agilite(0), m_endurence(0),
                                m_maitrise(0)
                                {}
                        
                            bool m_allie;
                            int m_x, m_y;
                            direction m_direction;
                            std::string m_nom;
                            int m_HP_Max, m_PA_Max;
                            int m_HP, m_PA, m_TE;
                            int m_force, m_magie;
                            int m_defense, m_esprit;
                            int m_agilite, m_endurence;
                            int m_maitrise;
                        };
                        
                        #endif
                        


                        Perso.h
                        La classe Perso, est aussi très simple, elle ne fait juste que contenir ses donnes (public). Justement ce que je voudrai ce serai de les mettre en private, mais que tous les derivés d'Action peuvent y accéder...

                        #ifndef PERSO_H
                        #define PERSO_H
                        
                        #include <string>
                        #include "Donnes_Perso.h"
                        
                        struct Perso
                        {
                            Perso(std::string nom, bool allie, int x, int y, direction direction) :
                                m_donnes(nom, allie, x, y, direction){}
                        
                            Donnes_Perso m_donnes;
                        };
                        
                        #endif
                        

                        Action.h
                        Maintenant la classe Action, elle est abstraite par sa méthode executer qui prend en paramètre un Combat (autre classe). Elle a en attribut le perso qui fait l'action. Elle a un autre attribut : l'epuisement, normalement a chaque "executer" le perso doit perdre l'epuisement dans son m_TE (qui est dans ses donnés: c'est son "Taux d'epuisement")
                        #ifndef ACTION_H
                        #define ACTION_H
                        
                        struct Perso;
                        struct Combat;
                        
                        struct Action
                        {
                            Action(Perso* perso, int epuisement) : m_perso(perso), m_epuisement(epuisement){}
                        
                            virtual void executer(Combat*) = 0;
                            virtual ~Action(){};
                        
                            Perso* m_perso;
                            protected : int m_epuisement;
                        };
                        
                        #endif
                        


                        Combat.h
                        La classe qui fait tout. Elle a déjà un attribut m_limite, mais on s'en fout. Elle a aussi une méthode afficher qui afficher, mais elle marche très bien, et on s'en fout aussi. Ce qui est important c'est la méthode action(), et les 2 liste<Action*> de chaque joueur.
                        Cette méthode regarde les 2 première actions de chaque liste et fait "executer" celle qui est le plus rapide (en fonction des données des perso qui font les actions).
                        Les méthodes de cette class marchent très bien, je ne vais montrer seulement le .h

                        A un dernier "petit" detail, il hérite de map<string, Perso*>, mais ca aussi on s'en fout.

                        #ifndef COMBAT_H
                        #define COMBAT_H
                        
                        #include "Action.h"
                        #include "Perso.h"
                        #include <map>
                        #include <list>
                        #include <SFML/Graphics.hpp>
                        
                        struct Combat : std::map<std::string, Perso*>
                        {
                            void action();
                            void afficherCarte(sf::RenderWindow &app);
                        
                            std::list<Action*> m_liste1;
                            std::list<Action*> m_liste2;
                            sf::IntRect m_limite;
                        };
                        
                        #endif
                        


                        Alors maintenant quelques dérivés d'Action pour exemple: Deplacer, Attaquer
                        Ils ont juste une redifinition de la méthode executer, avec quelques attributs en plus, et on peut remarquer que la méthode termine toujours par
                        m_perso->m_donnes.m_TE -= m_epuisement;
                        


                        Alors voila les classe
                        struct Deplacer : Action
                        {
                            Deplacer(Perso* perso, direction direction) : Action(perso, 1), m_direction(direction){};
                        
                            void executer(Combat*)
                            {
                                int x(m_perso->m_donnes.m_x), y(m_perso->m_donnes.m_y);
                        
                                switch(m_direction)
                                {
                                    case HAUT : m_perso->m_donnes.m_y -= 1; m_perso->m_donnes.m_direction = HAUT; break;
                                    case BAS : m_perso->m_donnes.m_x += 1; m_perso->m_donnes.m_direction = BAS; break;
                                    case GAUCHE : m_perso->m_donnes.m_y -= 1; m_perso->m_donnes.m_direction = GAUCHE; break;
                                    case DROITE : m_perso->m_donnes.m_x += 1; m_perso->m_donnes.m_direction = DROITE; break;
                                }
                        
                                m_perso->m_donnes.m_TE -= m_epuisement;
                            }
                        
                            direction m_direction;
                        };
                        
                        struct Attaquer : Action
                        {
                            Attaquer(Perso* perso, Perso* cible) : Action(perso, 1), m_cible(cible){};
                        
                            void executer(Combat*)
                            {
                                m_cible->m_donnes.m_HP -= (m_perso->m_donnes.m_force - m_cible->m_donnes.m_defense);
                                if(m_cible->m_donnes.m_HP < 0) m_cible->m_donnes.m_HP = 0;
                        
                                m_perso->m_donnes.m_TE -= m_epuisement;
                            }
                        
                            Perso *m_cible;
                        };
                        


                        Donc en gros, 1 problème

                        Le gros: je voudrai pouvoir mettre les donnes du perso en private (en lecture seulement), mais faire en sorte que les dérivés d'Action puisse y accéder.


                        Et puis s'il y a des remarque sur l'organisation de mon code n'hésitez pas ;)
                        • Partager sur Facebook
                        • Partager sur Twitter
                          15 septembre 2011 à 19:22:23

                          C'est très exactement ce que fait le premier code que j'ai donné (premier message). Ce que te propose lmghs c'est de faire autrement, de ne pas laisser voir l'implémentation de la classe Perso en lui donnant une interface permettant d'appliquer tout type d'effet sans que l'extérieur (classe Action et dérivés) n'aient connaissance des données de Perso. Le but est donc justement de ne pas accéder à la partie private de Perso.
                          • Partager sur Facebook
                          • Partager sur Twitter
                            15 septembre 2011 à 19:27:57

                            :/
                            Tu m'as l'air de réfléchir en termes de données et non en termes de services à rendre pour te poser de telles questions.

                            Reregarde mon Effet::BouleDEuf::affecte()
                            Imagine maintenant que Cible::encaisse() soit:
                            Cible::encaisse(Degats dmg, Type t, Duree d, JP jp) {
                                // d'abord on détermine si on se prend des dégats, et en quelle quantité
                                if (this->hasImmunity(t)) return;
                                JpResult pirouette = this->reussitASeProteger(jp); // Cf les règles d20 de D&D pour les explications sur les jets de résistance.
                                if (pirouette == JP::SuccessTotal) return;
                                Degats dmg_finaux = this->applyResistances(dmg, t); // for each sur les résistances actives pour réduire les dégâts
                                if (pirouette == JP::SuccessHalf)
                                    dmg_finaux /= 2;
                                
                                // et maintenant, on applique les dégâts
                                if (dmg_finaux > m_hp) {
                                    m_hp = 0;
                                    m_etat. push(mort);
                                } else if (dmg_finaux == m_hp) {
                                    m_hp = 0;
                                    m_etat. push(inconscient);
                                } else {
                                    m_hp -= degat
                                }
                            }
                            

                            NB: je n'ai pas géré l'aspect durée: (des dégâts qui s’étendent sur plusieurs tours)

                            Et là, l'effet n'accède à aucune donnée privée de la cible. C'est la cible qui sait, et gère, comment encaisser des dégâts qu'on lui fait. Je n'ose imaginer le b*rd*l infâme que cela eut été si l'Effet avait dû aller piocher dans les particularités de la cible. Surtout que là, rien n'interdit de mettre en œuvre des spécialisations éventuelles -- quoique j'y pense qu'on y perdrait, et qu'il est plus simple de dire qu'une porte a des résistances contre les coups étourdissants, et les armes de pointe, une immunité contre la glace, etc que de dériver pour avoir un Porte::encaisse() spécialisé.

                            La spécialisation sera plus évidente sur les déplacements utile (et encore). Tu auras probablement des cibles que tu voudras non déplaçables (genre des arbres). Le truc est de définir un verbe déplacer() sur les Cible et de ne l'implémenter que sur certaines classes (C++) filles des Cibles.
                            • Partager sur Facebook
                            • Partager sur Twitter
                            C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                              15 septembre 2011 à 20:14:29

                              Je pense vraiment avoir compris vos 2 solutions (enfin ^^ )
                              Celle de De passe:
                              Le problème c'est que la classe Action, a besoin pas seulement des donnés d'un personnage, mais de la classe en général

                              Celle de lmghs:
                              Le problème c'est que les actions sont un peu tout, un déplacement, une soutien, une attaque, donc comment la cible peut savoir quoi faire...
                              • Partager sur Facebook
                              • Partager sur Twitter
                                15 septembre 2011 à 20:24:49

                                Un soutien, c'est un ensemble complexe d'action unitaires.
                                C'est à l'IA de faire en sorte de positionner la bestiole en soutien et de choisir le moyen de soutenir (attaque, magie, soin, bloquer la ligne de vue, fermer une porte, etc)
                                Les actions unitaires provoquent un ensemble d'effet unitaires. Tous les effets possibles doivent être implémentés avec une approche respectueuse de l'encapsulation/la loi de Déméter.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                                  16 septembre 2011 à 17:46:08

                                  J'ai essayé de comprendre, mais j'ai rien compris, le lien avec l'IA, la loi de Déméter (j'ai fait une recherche mais je vois pas le rapport), ou les actions unitaires.

                                  Que faut-il faire concrètement dans mon code?...
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    17 septembre 2011 à 20:15:06

                                    Je vais essayer de redire ce qu'à dit lmghs (il me corrigera au besoin). L'idée c'est que ton perso n'a pas besoin de pouvoir traiter spécifiquement chaque type d'action. Il lui suffit d'offrir une interface suffisante pour altérer l'état de l'objet (c'est ce que fait encaisser par exemple). C'est ensuite aux actions d'utiliser cette interface pour altérer l'objet. En gros, le perso n'a pas besoin de connaitre la nature des actions, il a seulement besoin de pouvoir être altérer, c'est aux actions de savoir comment altérer les persos.

                                    Demandes toi quel doit être l'interface de ta classe personnage (oublie les données membres dans un premier temps), une fois que tu auras ton interfaces tu rajouteras tes données membres et l'implémentation de ton interface. (fais un interface minimal dans un premier temps, ca te permettra de voir si ce que tu fais est viable plus rapidement AMA)

                                    struct People
                                    {
                                      void affect(/*some data*/)
                                      { /*no matter*/ }
                                      //other, some with return-value
                                      private:
                                        //data : no matter
                                    };
                                    
                                    struct AnAction
                                    {
                                      void run_on(People& p)
                                      {
                                        p.affect();
                                        //and/or complex code
                                        //using interface of p
                                        //perhaps with value-return
                                        //and data members
                                      }
                                      //other functions and/or data members
                                    };
                                    

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    FaQ : Fr | En 1 2 | C++11 | Template || Blog : Deloget | C++|Boost--Dev | C++Next | GotW || Installer Boost
                                      17 septembre 2011 à 22:15:38

                                      Si je comprend bien, c'est le Perso qui offre la possibilité à une action de la changer, en utilisant le méthode affect()
                                      Mais comment être sur que seulement une Action utilisera cette interface? :-°
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        17 septembre 2011 à 22:31:39

                                        Je vois pas trop l'interet d'une telle limitation. Tout ceux qui auront acces à un personnage pourront utiliser cet élément de l'interface, mais je ne vois pas en quoi c'est un problème. Au final seul ceux qui ont besoin d'altérer l'objet le feront. L'interface ne fait qu'offrir des possibilités (elle garantie aussi la conservations des invariants et d'un état sémantiquement correct pour l'objet, ce qui n'est "pas" le cas sans encapsulation), en aucun cas elle ne force à utiliser ces possibilités.

                                        A chaque fois que tu utilises std::string tu n'es pas obligé d'utiliser l'interface complète de std::string, là c'est pareil, les différents acteurs utiliseront ce qu'ils ont besoin de l'interface. Et si ton interface est bien construite (et ton architecture aussi), le fait qu'autre chose qu'une action utilise ces éléments de l'interface ne sera pas forcément une mauvaise chose.
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        FaQ : Fr | En 1 2 | C++11 | Template || Blog : Deloget | C++|Boost--Dev | C++Next | GotW || Installer Boost
                                          17 septembre 2011 à 22:57:56

                                          Citation : Freedom

                                          ...(elle garantie aussi la conservations des invariants et d'un état sémantiquement correct pour l'objet, ce qui n'est "pas" le cas sans encapsulation)...



                                          Je ne comprend pas trop cette partie de ta réponse car pour moi c'est comme sans encapsulation...
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            17 septembre 2011 à 23:30:41

                                            Le fait de passer par une interface et non directement par des données (ie l'encapsulation : penser en terme de services), permet 2 choses :

                                            - Indépendance du reste du programme par rapport à la représentation interne des données : on peut changer les données (et donc l'implémentation de l'interface) sans que ca affecte le reste du code.

                                            - Conserver un état sémantiquement correcte : quand tu as un objet d'un certains type avec une collection de données, un état quelconque de ces données n'a pas forcément de sens. Le fait d'avoir une interface qui propose différents services permet de garantir que l'ensemble des données restera cohérant.
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            FaQ : Fr | En 1 2 | C++11 | Template || Blog : Deloget | C++|Boost--Dev | C++Next | GotW || Installer Boost
                                              18 septembre 2011 à 11:07:46

                                              J'ai pas compris ton premier point, sans encapsulation il y a aussi une indépendance, quand on change les donnés ca n'affecte pas le reste du code.
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                18 septembre 2011 à 14:28:48

                                                struct DataType
                                                {
                                                  void bar()
                                                  {}
                                                };
                                                
                                                struct A
                                                {
                                                  DataType d;
                                                };
                                                
                                                class B
                                                {
                                                  A a;
                                                  public:
                                                    void foo()
                                                    { a.d.bar(); }
                                                };
                                                


                                                Si je change les donnée membres de A, je peut être amené à faire une correction dans l'implémentation de B::foo (parceque la donnée peut ne plus s'appeler d ou ne plus avoir de fonction membre foo).

                                                Si je pense en terme de service ca donne ca :

                                                struct A
                                                {
                                                  void service()
                                                  { /*no matter, could use data members*/ }
                                                  private:
                                                    //data members : no matter
                                                };
                                                
                                                class B
                                                {
                                                  A a;
                                                  public:
                                                    void foo(à
                                                    { a.service(); }
                                                }
                                                


                                                Cette fois je peux changer les donnée membres de A tant que je veux, ca ne fera changer que l'implementation de l'interface de A et rien d'autre.

                                                PS: Dans le premier code tu peux voir un viol de la loi de Demeter au passage.
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                FaQ : Fr | En 1 2 | C++11 | Template || Blog : Deloget | C++|Boost--Dev | C++Next | GotW || Installer Boost
                                                  18 septembre 2011 à 18:28:29

                                                  Et comment la fonction B::foo, explique à la fonction A::service, ce qu'elle lui demande de faire.
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    18 septembre 2011 à 18:50:06

                                                    C'est un exemple abstrait. Si la classe A est bien faite, son interface fournit l'ensemble des services nécessaire, B::foo n'a plus qu'à utiliser ce qu'elle a besoin. Les données membres et l'implémentation de l'interface de A peuvent changer autant qu'ils veulent (*) ca n'aura aucun impact sur B (l'ensemble des services n'est plus amené à évoluer une fois determiné et validé, ou alors c'est un problème de conception ...).

                                                    Dans ton cas c'est la classe représentant tes personnages qui doit offrir un ensemble de services complet (et cohérant -> SRP), ensuite le reste de ton code utilisera cette interface (les actions quelquel soit par exemple), peu importe comment seront représentées les données de ta classe perso (des int, un tuple, des intervalles, autre ?).

                                                    Cette indépendance offre vraiment un atout. Imagines que ton projet est bien avancé et que tu as déjà une belle collection d'action (en "dur" ou scripté, peu importe), et là tu te rend compte que tu peux changer ta représentation des données de ton personnage (disons que tu as trouvé un algo matriciel qui serait plus avantageux que gérer un à un des int (**) ), si tes actions utilises les données membres tu te retrouves à devoir recoder toutes tes actions (et si tu avais developpé un outil externe pour la création de script, tu te retrouve à refaire une partie de cet outil (***) ), alors que si ces actions ne font qu'utiliser une interface bien pensée, ce changement ne se fera ressentir que dans l'implémentation de l'interface (mise en place de super algo matriciel).

                                                    (*) C'est quelque chose qui peut arriver facilement, pour optimiser un algorithme (interne à A) par exemple : changement de la représentation des données et donc de la facon de les manipuler.

                                                    (**) C'est un exemple bidon, je n'ai rien de précis en tête.

                                                    (***) Tu n'en es pas encore là, mais pense à la force apporté par les script, ca permet de ne pas recompiler (faut pas scripter n'importe quoi, mais pour les ressources comme les compétences/actions, ca peut servir), à chaque innovation que tu apporteras. Et ca permet en developpant à coté un petit programme pour aider à générer ces script, de laisser la création de ressources à d'autres personnes pour te concentrer sur le reste du developpement : ce qui demande de réel compétences en programmation.
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                    FaQ : Fr | En 1 2 | C++11 | Template || Blog : Deloget | C++|Boost--Dev | C++Next | GotW || Installer Boost
                                                      18 septembre 2011 à 19:50:07

                                                      Oui, tout ca je le comprend, mais, voilà mon code. (la classe Perso s'est transformé en Combat ;) )

                                                      Alors d'abord la classe Action
                                                      #ifndef ACTION_H
                                                      #define ACTION_H
                                                      #include <string>
                                                      
                                                      struct Combat;
                                                      
                                                      struct Action
                                                      {
                                                          Action(std::string const& perso, int epuisement) : m_perso(perso), m_epuisement(epuisement){}
                                                      
                                                          virtual void executer(Combat&) = 0;
                                                          virtual ~Action(){};
                                                      
                                                          std::string m_perso;
                                                          protected : int m_epuisement;
                                                      };
                                                      
                                                      #endif
                                                      


                                                      Classe toute simple, à préciser que le taux d'épuisement ne sert à rien pour le moment

                                                      Maintenant la classe Combat
                                                      #ifndef COMBAT_H
                                                      #define COMBAT_H
                                                      
                                                      #include "Action.h"
                                                      #include "Perso.h"
                                                      #include <map>
                                                      #include <list>
                                                      #include <SFML/Graphics.hpp>
                                                      
                                                      struct Combat
                                                      {
                                                          void ajouterPerso(Perso &perso);
                                                      
                                                          void action();
                                                          std::list<Action*> m_liste1;
                                                          std::list<Action*> m_liste2;
                                                      
                                                          void afficherCarte(sf::RenderWindow &app);
                                                          sf::IntRect m_limite;
                                                      
                                                          private : std::map<std::string, Perso> m_persos;
                                                      };
                                                      
                                                      #endif
                                                      


                                                      Cette classe à comme attribut (les données ;) ) une std::map qui regroupe les Perso par leurs nom.
                                                      La fonction ajouterPerso ajoute un perso dans la map.
                                                      La fonction afficherCarte et l'attribut m_limite, ne sont pas utiliser pour l'instant.

                                                      Maintenant la fonction action et les 2 liste.
                                                      Les 2 liste peuvent être modifiés à tout moment par l'utilisateur, puisqu'elle sont public.
                                                      Quant a la méthode action, elle fait qu'utiliser "executer" sur une des action des listes.

                                                      Bon je crois que j'ai fait le tours du code. Place au problème

                                                      Comment la méthode Action::executer(Combat&) peut accéder à la std::map privé du combat en paramètre?


                                                      Il faut donc, si j'ai bien compris, faire une interface au Combat pour que l'action puisse le modifier

                                                      Mais c'est quoi cette interface? Est-ce que cette interface serai une méthode qui permettrai de modifier la std::map du Combat? Une sorte de "void set...()..."


                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        19 septembre 2011 à 20:02:21

                                                        Je up, avec

                                                        Citation : Sephirotte


                                                        Mais c'est quoi cette interface? Est-ce que cette interface serai une méthode qui permettrai de modifier la std::map du Combat? Une sorte de "void set...()..."




                                                        et puis je viens de relire ce premier message

                                                        Citation : De passage

                                                        L'amitié ne s'hérite pas (tu as posté la question sur le forum il y a peu).
                                                        Une solution à la volée : sépare tout ce qui relève de la donnée à l'intérieur de Personnage dans une classe Data_Perso et envoie ça à ta fonction virtuelle.
                                                        Code explicatif (non testé) :

                                                        struct Data_Perso
                                                        {
                                                            //des données
                                                        };
                                                        
                                                        class Action
                                                        {
                                                            public :
                                                                virtual ~Action() = 0;
                                                                void doAction(Data_Perso& data) const {do_action(data);} //Edit : do est un mot-clé
                                                        
                                                            private :
                                                                virtual void do_action(DataPerso&) const {}
                                                                
                                                        };
                                                        
                                                        class Perso
                                                        {
                                                            public :
                                                                void apply(const Action& action) {action.doAction(_data);}
                                                                //Le reste de l'interface
                                                            private :
                                                                Data_Perso _data;
                                                        };
                                                        


                                                        Et bien je pourrai très bien faire ca avec ma map, mais est-ce que c'est une bonne chose, ou mieux vaut faire l'interface?
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          19 septembre 2011 à 20:29:09

                                                          Tu peux déjà avoir un doute avec ton code en voyant que Action et Combat dépendent l'un de l'autre, les dépendances circulaires peuvent devenir très génantes du point de vue conception (évolutions des deux éléments lié : pourquoi avoir 2 classes si il faut à chaque fois recoder les 2 ?).

                                                          J'aurais plutôt vu un truc comme ca :
                                                          #include<functional>
                                                          #include<utility>
                                                          #include<vector>
                                                          #include<algorithm>
                                                          
                                                          #include<iostream>
                                                          
                                                          enum DmgKind {physic /*other*/};
                                                          
                                                          struct People
                                                          {
                                                            People() : life(100) {}
                                                            void receive_dmg(DmgKind, size_t d)
                                                            { d > life ? life = 0: life -= d; 
                                                              //probably more complex
                                                              std::cout << life; /*trace*/ }
                                                          
                                                            private:
                                                              //other
                                                              size_t life;
                                                          };
                                                          
                                                          //FIFO with some specificities
                                                          struct Interaction
                                                          {
                                                            //some typedef for convenience
                                                            typedef std::function<void ()> Action;
                                                            typedef std::pair<Action,size_t> ActionAndSpeed;
                                                            typedef std::vector<ActionAndSpeed> Actions;
                                                          
                                                            //fill FIFO
                                                            void add_actions(Actions&& a)
                                                            { std::sort(a.begin(),a.end(),
                                                                [](const ActionAndSpeed& lhs,
                                                          	  const ActionAndSpeed& rhs)
                                                                { return lhs.second > rhs.second; } ) ;
                                                              std::for_each(a.begin(),a.end(),
                                                          	  [&](const ActionAndSpeed& a)
                                                          	  { actions_impl.push_back(a.first); } ) ; }
                                                            //trick to reuse code and provide lvalue and rvalue interface
                                                            void add_actions(Actions& a)
                                                            { add_actions(std::move(a)); }
                                                          
                                                            //return the state of FIFO
                                                            //could be usefull for other function
                                                            bool process()
                                                            { (*actions_impl.begin())();
                                                              actions_impl.erase(actions_impl.begin()); 
                                                              return actions_impl.empty(); }
                                                          
                                                            private:
                                                              typedef std::vector<Action> ActionsImpl;
                                                          
                                                          	ActionsImpl actions_impl;
                                                          };
                                                          
                                                          //an action : should be script
                                                          void hit(People& p, size_t d)
                                                          { p.receive_dmg(physic, d); }
                                                          
                                                          int main()
                                                          {
                                                            //two people
                                                            People p1, p2;
                                                          
                                                            //an interaction
                                                            Interaction i;
                                                            //who have to create it ? IA, "environment" ?
                                                          
                                                            //should be in a block that make junction between some IA
                                                            Interaction::Actions container;
                                                            container.push_back(
                                                          	Interaction::ActionAndSpeed(std::bind(hit,p1,10),1));
                                                            container.push_back(
                                                          	Interaction::ActionAndSpeed(std::bind(hit,p2,15),2));
                                                            i.add_actions(container);
                                                            while(!i.process()) {}
                                                          }
                                                          


                                                          NB: C'est surment pas parfait, mais je supprime déjà les inter-dépendance et je supprime toute dépendance du système à la nature réel des actions.
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                          FaQ : Fr | En 1 2 | C++11 | Template || Blog : Deloget | C++|Boost--Dev | C++Next | GotW || Installer Boost

                                                          Problème d'Amitié

                                                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                          • Editeur
                                                          • Markdown