Partage
  • Partager sur Facebook
  • Partager sur Twitter

Classe virtuelle pure en argument

    11 novembre 2017 à 10:34:13

    Hey :)

    J'ai un soucis avec les arguments d'une de mes fonctions.

    J'ai une classe virtuelle pure qui s'appelle Role. Ses classes filles sont donc tous les roles qui sont disponibles.

    Un joueur doit avoir un role, qui est donc un objet qui hérite de la classe Role. Pour ce faire, j'ai créé une fonction setRole:

    void Player::setRole(Role role)
    {
    	m_role = role;
    }

    Et c'est la que ca coince : Role est une abstraite pure, du coup, il refuse de compiler, ce qui est logique. 

    mais du coup je me retrouve coincé, parce que je voudrais faire des trucs comme ca :

    Magicien magicien; //Magicien hérite donc de Role
    joueur.setRole(magicien);

    et je ne peux donc pas :/

    Des idées ? Je pourrais aussi juste mettre Role en abstrait, et enlever la mention pure mais c'est un peu nul :/


    • Partager sur Facebook
    • Partager sur Twitter
    3D Graphics are a lie
      11 novembre 2017 à 11:48:07

      Le fait que ton role soit abstrait ou juste héritable n'est pas le probleme ici.
      Il faut comprendre la problématique d'héritage, et ce que ça entraine sur le niveau "copiabilité" d'un type, si il manipulé comme un type parent.
      Ici, en paramètre de ta fonction, tu as un objet de type Role, donc tu as une copie en entrant dans la fonction, le type copié sera de type Role, sans les potentiels variation des types enfant (tu as très certainement pareil au niveau de m_role).

      Tu peut passer ton Role par référence, et l'assigner sur un pointeur interne (en faisant attention que ton role ai une durée de vie au moins égal a ton player).
      Tu peu aussi utiliser un unique_ptr si tu veut que ton Player ai la responsabilité du Role qu'il possède.
      Donc, vu que ton type est héritable, il ne doit pas pouvoir être copiable, donc tu peut le rentre non copiable.

      Je t'invite a aller mieux t'informer au niveau des héritages, et des sémantiques (entités/valeur) de class.

      Par exemple ici :
      http://guillaume.belz.free.fr/doku.php?id=programmez_avec_le_langage_c

      -
      Edité par n!co69 11 novembre 2017 à 11:49:30

      • Partager sur Facebook
      • Partager sur Twitter
      "Tout devrait être rendu aussi simple que possible, mais pas plus." A.Einstein
        11 novembre 2017 à 12:26:23

        Merci de ta réponse :) 

         Ici, en paramètre de ta fonction, tu as un objet de type Role, donc tu as une copie en entrant dans la fonction, le type copié sera de type Role, sans les potentiels variation des types enfant (tu as très certainement pareil au niveau de m_role).

        Ca signifie que si j'appelle une fonction de m_role, j'aurai pas la version overridée ?! Mais c'est sacrément embettant ca ! :/ 

        Et au dela de ca du coup j'essaie de faire comme tu as dit :

        void Player::setRole(Role &role)
        {
        	m_role = &role;
        }

        et 

        Role* m_role;

        et j'obtiens une erreur comme quoi on peut pas instancer une classe abstraite.

        Meme chose si je fais 

        std::unique_ptr<Role> m_role;
        void Player::setRole(Role &role)
        {
        	m_role = std::make_unique<Role>(role);
        }
        

        :euh:




        -
        Edité par Euxiniar 11 novembre 2017 à 12:27:25

        • Partager sur Facebook
        • Partager sur Twitter
        3D Graphics are a lie
          11 novembre 2017 à 12:29:52

          Pour le coup du make_unique, regarde comment ça marche, tu as ici une copie a sa construction. Il faut que ton Role soit unique dés le départ, et tu le move dans ta class (tu as plus d'infos la dessus dans le tuto plus haut).
          Pour la ref, ta copie est ailleurs.
          • Partager sur Facebook
          • Partager sur Twitter
          "Tout devrait être rendu aussi simple que possible, mais pas plus." A.Einstein
            11 novembre 2017 à 12:33:11

            Euxiniar a écrit:

            Ca signifie que si j'appelle une fonction de m_role, j'aurai pas la version overridée ?! Mais c'est sacrément embettant ca ! :/ 


            Garde bien en tête que pour profiter pleinement de l'héritage, tu dois utiliser des références ou des pointeurs (de préférence: intelligents).
            • Partager sur Facebook
            • Partager sur Twitter
              13 novembre 2017 à 10:25:47

              Salut.

              Quand tu fais une hiérarchie d'objets polymorphiques, tu dois passer tes objets par référence sur la classe de base (ca dit au comilateur : je référence un objet, qui est soit le type de base, soit le type dérivé).

              Si tu passes des objets par copie (bêtise), tu dis au compilateur : prend mon objet dérivé, et convertit le, de manière implicite, dans son type de base, puis passe le type de base. Tu ne veux généralement JAMAIS faire ca. Pour te prévenir de ce genre de bêtises, penses a mettre les constructeurs du type de base en protected.

              Ensuite va lire la doc de std::unique_ptr, je pense aussi qu'il y a un moment ou tu voudra soit faire voyager des objets dérivés, soit mettre des objets hétérogènes héritants d'une même classe de base dans un container, et c'est la solution à retenir.

              • Partager sur Facebook
              • Partager sur Twitter
                15 novembre 2017 à 12:47:39

                Mince ! j'ai pas répondu depuis un certain temps, désolé, je serai fouetté au sang pour la peine !

                Merci pour les astuces du constructeur en protected, c'est une bonne idée. J'ai cherché a utiliser l'unique_ptr, mais j'ai pas vraiment réussi. Du coup, je me suis que dans le doute, je pouvais tenter d'utiliser un passage d'un shared_ptr, et puis la, mystere et boule de gomme, ca fonctionne x)

                je vous envoie la def de la fonction:

                void Player::setRole(std::shared_ptr<Role> role)
                {
                	m_role = role;
                }

                concrètement je vois pas trop la diff avec un unique_ptr, mais le fait est que la j'ai plus de soucis. 

                • Partager sur Facebook
                • Partager sur Twitter
                3D Graphics are a lie
                  15 novembre 2017 à 12:57:23

                  Tu devais passer ton unique_ptr par copie alors qu'il n'est pas copiable. N'utilise pas shared_ptr pour rien. Ici ça n'a pas de sens.

                  PS: ce setter est très crado. Pourquoi ne pas fournir le rôle à la construction simplement ?

                  • Partager sur Facebook
                  • Partager sur Twitter

                  Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

                    16 novembre 2017 à 19:54:24

                    Pfiou ! J'aurai galéré mais du coup ca y est ! Et puis qui suis je, pour ne pas écouter les conseils de Ksass Peuk ?! :lol:

                    Et du coup je vais modifier ma classe pour qu'elle ait directement le role Ksass :)

                    classTest::classTest(std::unique_ptr<firstClass> &&first) : f(std::move(first))
                    {
                    }
                    

                    Après vérif et test, plusieurs joueurs peuvent avoir le meme role, par conséquent, l'unique_ptr est pas adapté, puisqu'il appartient a un joueur unique. Du coup, le shared fait mieux le taf.
                    Pour ce qui est de ma fonction setter, je vois pas trop comment modifier ca, parce que je crée mes joueurs bien avant de leur donner un role.

                    Alors je pourrais trimbaler toutes les caractéristiques d'un joueur dans différents tableaux pendant 10 ans, jusqu'au moment de savoir quel role je vais lui assigner, mais je suis pas sur que ca soit beaucoup plus propre :lol:

                    -
                    Edité par Euxiniar 16 novembre 2017 à 22:11:19

                    • Partager sur Facebook
                    • Partager sur Twitter
                    3D Graphics are a lie
                    Anonyme
                      19 novembre 2017 à 11:42:35

                      En fait, tu utilises une classe virtuelle pure comme enumeration...

                      Je te conseilles cette solution, qui est plus propre

                      enum class Role
                      {
                          //les differents roles de ton perso
                          MAGICIEN, GUERRIER, PROGRAMMEUR //etc...
                      };

                      et ca s'utilise comme ca

                      void Player::setRole(Role role)
                      {
                          //ici, pas besoin de pointeurs ou de references
                          m_role = role;
                      }

                      avec comme appel

                      Player player;
                      
                      //ne pas oublier le Role::VALUE
                      player.setRole(Role::PROGRAMMEUR);



                      C'est plus simple a gerer et plus propre.

                      En revanche, c'est vrai qu'il vaudrait quand meme mieux apprendre a bien gerer l'heritage.

                      -
                      Edité par Anonyme 19 novembre 2017 à 11:54:40

                      • Partager sur Facebook
                      • Partager sur Twitter
                        19 novembre 2017 à 14:38:28

                        BorisD a écrit:

                        En fait, tu utilises une classe virtuelle pure comme enumeration...

                        Sauf si le rôle est simplement ce qu'on appelle une stratégie, auquel cas, c'est bien plus malin que ce qui est présenté typiquement dans le tutoriel d'OC.

                        BorisD a écrit:

                        Je te conseilles cette solution, qui est plus propre

                        Pas vraiment non, encore une fois le setter c'est le truc à ne pas faire.

                        • Partager sur Facebook
                        • Partager sur Twitter

                        Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

                        Anonyme
                          19 novembre 2017 à 18:41:38

                          Ksass`Peuk a écrit:

                          BorisD a écrit:

                          En fait, tu utilises une classe virtuelle pure comme enumeration...

                          Sauf si le rôle est simplement ce qu'on appelle une stratégie, auquel cas, c'est bien plus malin que ce qui est présenté typiquement dans le tutoriel d'OC.

                          BorisD a écrit:

                          Je te conseilles cette solution, qui est plus propre

                          Pas vraiment non, encore une fois le setter c'est le truc à ne pas faire.

                          Je ne comprend pas pourquoi tu dis que c'est moins propre, peux tu expliquer un peu plus? Et, cette strategie, c'est plus malin car elle contient des methodes virtuelles utilisables directement plutot que soumises a une condition, ou des trucs comme ca?

                          • Partager sur Facebook
                          • Partager sur Twitter
                            20 novembre 2017 à 0:52:34

                            Salut,

                            Le fait est que, généralement un "setXXX" tout simple ne représente aucun service "digne de ce nom" que l'on est en droit d'attendre de la part d'une classe.

                            Dans le cas présent, le joueur a d'office un rôle lorsqu'il est créé.  Il faut donc faire en sorte que ce rôle "de départ" lui soit donné à la création.

                            Par la suite, tu peux vouloir modifier le rôle d'un joueur, et, le cas échéant, faire des vérifications permettant de s'assurer que le role que tu donne au joueur est en adéquation avec son rôle précédant.

                            Or, le nom d'une fonction détermine son utilisation, sa raison d'être.  Si tu crées une fonction setRole, tu dit implicitement que tu modifie le rôle du joueur, sans rien faire de plus, et donc, sans qu'il n'y ait la moindre vérification possible.  Mais en plus, tu donnes à l'utilisateur de la classe l'occasion de faire "n'importe quoi".

                            Or, comme disait l'autre:

                            Il faut faire en sorte que l'utilisation correcte de la classe soit facile et qu'il soit difficile d'utiliser la classe de manière incorrecte

                            Du coup, une fonction changeRole (si elle a une raison d'être) correspondra bien mieux à un service que l'on est en droit d'attendre de notre classe. 

                            C'est d'autant plus vrai que l'on pourrait parfaitement du coup lui donner un paramètre qui ne serait pas déjà du type Role (mais une énumération, par exemple, ou n'importe quelle information qui pourrait lui permettre de créer le rôle "à la demande"), et que cela permettrait donc "centraliser" l'endroit où les rôles sont créés à un seul endroit dans le code, plutôt que d'avoir 36 disséminés un peu partout dans le code, qu'il faudra corriger à chaque fois que tu voudras rajouter un nouveau rôle potentiel ;)

                            • Partager sur Facebook
                            • Partager sur Twitter
                            Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                              20 novembre 2017 à 17:14:14

                              @koala01 merci pour ton éclaircissement, ca m'aide beaucoup mieux a comprendre pourquoi un setter c'est "mal" ^^ Du coup, vaudrait mieux faire une classe changeRole au lieu d'un set. Ce que j'ai pas bien compris c'est si je dois faire quelque chose comme un assert dans la fonction, ou si simplement je li fait renvoyer un booléen (0 pour ok et 1 pour pas ok).

                              Du coup, ce que vous conseillez de faire, c'est une sorte de factory à l'intérieur d'une fonction changeRole, qui utilise une énumération au lieu de roles?

                              • Partager sur Facebook
                              • Partager sur Twitter
                              3D Graphics are a lie
                              Anonyme
                                20 novembre 2017 à 19:38:15

                                Euxiniar a écrit:

                                @koala01 merci pour ton éclaircissement, ca m'aide beaucoup mieux a comprendre pourquoi un setter c'est "mal" ^^ Du coup, vaudrait mieux faire une classe changeRole au lieu d'un set. Ce que j'ai pas bien compris c'est si je dois faire quelque chose comme un assert dans la fonction, ou si simplement je li fait renvoyer un booléen (0 pour ok et 1 pour pas ok).

                                Du coup, ce que vous conseillez de faire, c'est une sorte de factory à l'intérieur d'une fonction changeRole, qui utilise une énumération au lieu de roles?


                                Ben, je sais pas, car

                                Ksass`Peuk a écrit:

                                BorisD a écrit:

                                En fait, tu utilises une classe virtuelle pure comme enumeration...

                                Sauf si le rôle est simplement ce qu'on appelle une stratégie, auquel cas, c'est bien plus malin que ce qui est présenté typiquement dans le tutoriel d'OC.

                                Du coup, si j'ai bien compris, ce serait mal d'utiliser des enumerations (meme fortement typees), meme si Ksass `Peuk ne m'a pas repondu pourquoi...

                                D'ailleurs: prefere les exceptions aux asserts, ca permet de corriger le tire en cas d'erreur.

                                -
                                Edité par Anonyme 20 novembre 2017 à 19:40:08

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  20 novembre 2017 à 19:46:10

                                  Roh, ils sont pas à la minute non ! :p

                                  Si on décide d'utiliser les rôles comme des stratégies, à savoir une fonctionnalité variante en fonction du rôle, effectivement on y gagne. Parce qu'avec l'énumération, on se retrouve juste à avoir du code du genre :

                                  switch(role){
                                  case TRUC: ...
                                  case MACHIN: ...
                                  case BIDULE: ...
                                  }

                                  Ce qui n'est pas pratique : si on veut rajouter un rôle on va devoir modifier tous les switchs de ce genre. Alors qu'à l'inverse, le Rôle sous forme d'une stratégie polymorphe nous permet de simplement déléguer l'appel au rôle :

                                  void something(){
                                    my_role.something();
                                  }

                                  Mais on peut faire encore mieux et oublier les choses du genre "J'ai un magicien donc je crées dans mon programme la notion de magicien comme un type". Et se dire simplement qu'un joueur va avoir une liste de capacités, et que le rôle ne fait finalement que déterminer cette liste de capacité. De cette manière, créer une nouveau rôle, c'est juste créer une nouvelle liste de capacité qu'on pourrait par exemple donner en entrée d'une fonction du joueur. On peut même en ajouter/enlever au cas par cas.

                                  BorisD a écrit:

                                  D'ailleurs: prefere les exceptions aux asserts, ca permet de corriger le tire en cas d'erreur.

                                  Soyons sélectifs : quand l'erreur est une erreur de programmation, il n'y a pas de tir à corriger à l'exécution, il faut corriger le code, et on ne veut pas que le développeur puisse y échapper, donc assertion. Si le développeur malgré toute sa bonne volonté ne peut pas contrôle l'erreur (plus de mémoire, connexion qui saute, fichier manquant, ...), alors effectivement, lançons lui une exception qu'il puisse traiter.

                                  -
                                  Edité par Ksass`Peuk 20 novembre 2017 à 19:48:17

                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

                                    20 novembre 2017 à 20:11:43

                                    Je suis désolé, j'ai un peu de mal a comprendre ou tu veux en venir ^^ Je me contente de renommer ma fonction setRole en changeRole, et j'ajoute des assert et c'est plié, ou je dois revoir completement mon architecture?

                                    Parce que quand je lis Mais on peut faire encore mieux et oublier les choses du genre "J'ai un magicien donc je crées dans mon programme la notion de magicien comme un type". Et se dire simplement qu'un joueur va avoir une liste de capacités, et que le rôle ne fait finalement que déterminer cette liste de capacité. Ce que je comprends c'est qu'en gros chaque joueur a la base a acces a toutes les fonctions des classes, et que le role est juste la pour "désactiver" certaines fonctions. Si c'est ca, ca me parait pas super opti non?

                                    Je rappelle que je veux simplement un joueur qui peut changer de role a tout moment, et qu'un role a des fonctionnalités qui lui sont propres, et communes.

                                    -
                                    Edité par Euxiniar 20 novembre 2017 à 20:14:51

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    3D Graphics are a lie
                                      20 novembre 2017 à 20:35:14

                                      Euxiniar a écrit:

                                      Ce que je comprends c'est qu'en gros chaque joueur a la base a acces a toutes les fonctions des classes, et que le role est juste la pour "désactiver" certaines fonctions. Si c'est ca, ca me parait pas super opti non?

                                      Le mot "optimisé" n'a rien à faire ici.

                                      Mais sinon, le joueur a accès à mieux. Il a juste une liste de capacités, qui ne sont pas des fonctions membres de la classe mais des objets.

                                      -
                                      Edité par Ksass`Peuk 20 novembre 2017 à 20:35:35

                                      • Partager sur Facebook
                                      • Partager sur Twitter

                                      Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

                                        20 novembre 2017 à 21:36:18

                                        ca veut dire que chaque fonction d'action du joueur devrait etre un objet indépendant?! Mais c'est super lourd !

                                        Honnêtement, je suis pas super vieux dans la prog, mais je suis quand meme surpris que tu conseilles de faire une classe par fonction o_O Je comprends tout de travers ou ca permet vraiment d'avoir un code plus maintenable?

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        3D Graphics are a lie
                                          20 novembre 2017 à 21:50:15

                                          Euxiniar a écrit:

                                          ca veut dire que chaque fonction d'action du joueur devrait etre un objet indépendant?! Mais c'est super lourd !

                                          Cela dépend de ce qu'on appelle une fonction d'action. Et c'est quoi le plus lourd une classe avec 12 fonctions de 5 pieds de longs, ou une douzaines de classes qui font approximativement rien ?

                                          Partons juste d'un constat super simple : c'est quoi la différence entre lancer un sort d'attaque qui consomme 12 de manas, à maximum 14 de distance et fait 7 de dégats, et lancer une attaque physique qui fait 8 de dégâts ? Ben c'est juste l'affichage, qui n'a rien à faire dans le code actuel. Parce que le second est en fait une attaque magique à 0 de manas et 0 de distance. Donc peut être qu'on peut donner un nom plus pertinent à ça.

                                          • Partager sur Facebook
                                          • Partager sur Twitter

                                          Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

                                            20 novembre 2017 à 22:51:44

                                            okay d'ac merci pour tes élaircissements !
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            3D Graphics are a lie
                                            Anonyme
                                              24 novembre 2017 à 18:36:31

                                              Ce qui peut etre vraiment efficace, ce serait une classe de traits contenant chacune de ces methodes.

                                              class Perso
                                              {
                                                  //m_hp : vie restante au perso
                                                  short int m_hp;
                                              
                                                  //m_name : nom du perso
                                                  std::string m_name;
                                              
                                                  //traits dont differents perso peuvent heriter
                                                  static struct Traits
                                                  {
                                                      typedef class WeaponContainer
                                                      {
                                                          std::unique_ptr<Weapon> m_weapon;
                                                          void hit();
                                                      }WeaponContainer;
                                                  };
                                              };

                                              Ce n'est evidemment qu'une version abregee, mais ca peut etre utile.

                                              -

                                              Edit:

                                              typedef n'est plus beaucoup utilise, mais est remplace par using. N'hesitez pas si vous connaissez autre chose!

                                              -
                                              Edité par Anonyme 25 novembre 2017 à 13:46:53

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                24 novembre 2017 à 23:44:37

                                                @BorisD: En fait non, c'est pas efficace. Si je considère un PNJ brigand, il aura probablement une arme dont il se servira pour détrousser les voyageurs, sauf que c'est pas un perso, c'est un PNJ, de même un tigre qui sera un typiquement un mob mais pourra devenir temporairement ou de façon permanente un allié, ne pourra pas coller à ce design. Si mon perso est magicien, il utilisera des sorts, du coup il lui faudra un SpellContainer plutôt qu'un WeaponContainer, et là encore, on se rend bien compte que ça va rapidement devenir ingérable... Et je ne parle même pas d'un guerrier mage qui pourra avoir des armes et des sorts, là ça devient carrément cauchemardesque...

                                                Pour se sortir de ce merdier, la notion d'objet ne fonctionne clairement pas. Imaginons que mon perso apprivoise un loup, il combattra à mes côtés, quelle est la différence entre un loup de base et ce loup là? Imaginons une autre scène, je tue un brigand, il a une arme bien meilleure que la mienne, que vais je faire? pas besoin d'être grand clerc pour comprendre que je vais vouloir m'emparer de son arme. Comment va tu matérialiser le fait que mon perso s'empare de cette arme, comment va tu matérialiser qu'un tigre se bat à mes côté?

                                                -
                                                Edité par int21h 25 novembre 2017 à 0:17:44

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
                                                Anonyme
                                                  25 novembre 2017 à 13:46:25

                                                  int21h a écrit:

                                                  @BorisD: En fait non, c'est pas efficace. Si je considère un PNJ brigand, il aura probablement une arme dont il se servira pour détrousser les voyageurs, sauf que c'est pas un perso, c'est un PNJ, de même un tigre qui sera un typiquement un mob mais pourra devenir temporairement ou de façon permanente un allié, ne pourra pas coller à ce design. Si mon perso est magicien, il utilisera des sorts, du coup il lui faudra un SpellContainer plutôt qu'un WeaponContainer, et là encore, on se rend bien compte que ça va rapidement devenir ingérable... Et je ne parle même pas d'un guerrier mage qui pourra avoir des armes et des sorts, là ça devient carrément cauchemardesque...

                                                  Pour se sortir de ce merdier, la notion d'objet ne fonctionne clairement pas. Imaginons que mon perso apprivoise un loup, il combattra à mes côtés, quelle est la différence entre un loup de base et ce loup là? Imaginons une autre scène, je tue un brigand, il a une arme bien meilleure que la mienne, que vais je faire? pas besoin d'être grand clerc pour comprendre que je vais vouloir m'emparer de son arme. Comment va tu matérialiser le fait que mon perso s'empare de cette arme, comment va tu matérialiser qu'un tigre se bat à mes côté?

                                                  A ce moment, on peut aussi le faire heriter d'un Perso,  d'un WeaponContainer, et d'un SpellContainer. Il est possible, aussi, d'utiliser ces strategies qui font l'objet de cette discussion, notamment, pour gerer les IA, comme les loups apprivoises. Si tu pensais a une meilleure solution, j'aimerais bien la connaitre.

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    25 novembre 2017 à 18:21:10

                                                    BorisD a écrit:

                                                    A ce moment, on peut aussi le faire heriter d'un Perso,  d'un WeaponContainer, et d'un SpellContainer. Il est possible, aussi, d'utiliser ces strategies qui font l'objet de cette discussion, notamment, pour gerer les IA, comme les loups apprivoises. Si tu pensais a une meilleure solution, j'aimerais bien la connaitre.

                                                    Sauf que, d'un point de vue conceptuel, on ne peut pas dire qu'un personnage EST un WeaponContainer ou un SpellContainer.  Au mieux, on peut estimer qu'il utiliser de tels éléments, voire qu'il est implémenté en terme de tels éléments, mais surment pas qu'il est une spécialisation de ceux-ci...

                                                    De plus, une relation d'héritage poserait de nombreux problèmes en termes d'interface, car, à moins d'utiliser des fonctions dont le nom est particulièrement explicite (comme equipSpell, equipWeapon, buySpell, buyWeapon, ou autre) -- ce qui serait un comble, car on se doute qu'un SpellContainer permet l'utilisation ... d'un sort et qu'un WeaponContainer permet l'utilisation... d'une arme -- un SpellContainer et un Weapon présenteront une interface sensiblement identique: equip, loot, buy, et les autres.

                                                    Du coup, si tu fais hériter une classe perso de WeaponContainer et de SpellContainer, tu vas te retrouver avec des conflits et des ambiguités sans nom.

                                                    Ce que tu peux éventuellement faire, c'est effectivement, créer une hiérarchie de classe pour les différents container, qui interviendraient dans une implémentation du patron de conception strategie, MAIS, ton personnage devra UTILISER cette stratégie, et non en hériter.

                                                    Quoi qu'il en soit, les règles combinatoires font que, pour N roles, tu risques de te retrouver avec N! combinaisons possibles. C'est à dire que tu dois t'attendre à avoir 120 combinaisons possibles pour seulement 5 rôles! Et à ce moment là, tu  n'en sortira déjà plus...

                                                    Or, il est facile d'avoir cinq roles différents: des classes Wizard, Warrior, Scoot et Tieth t'en font déjà 4(24 combinaisons possibles).  Rajoute deux spécialité à cela, et tu te retrouve avec 720 combinaisons possibles!

                                                    Bien sur, toutes les combinaisons ne seront pas *** forcément *** mises en oeuvre, mais... tiens tu vraiment à prendre le risque???

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                    Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                                                    Anonyme
                                                      26 novembre 2017 à 10:41:40

                                                      OK, je me rend. Du coup, qu'est ce que je peux faire? Utiliser ces strategies dont on parle depuis tout a l'heure? Mais du coup, je m'y prend comment? Je les fait heriter d'une classe Capacities pour les stocker dans un std::unique_ptr (que je n'arrive toujours pas a utiliser) ou un simple pointeur si je m'occupe de lui dans le destructeur?
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        26 novembre 2017 à 11:41:25

                                                        BorisD a écrit:

                                                        Je les fait heriter d'une classe Capacities pour les stocker dans un std::unique_ptr (que je n'arrive toujours pas a utiliser)

                                                        C'est une solution très simple qui marche bien (même si on peut faire encore plus flexible avec des schémas comme l'Entity Component System). Pour unique_ptr, si tu n'es pas plus précis que ça, ça va être compliqué de t'aider.

                                                        • Partager sur Facebook
                                                        • Partager sur Twitter

                                                        Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

                                                        Anonyme
                                                          26 novembre 2017 à 20:02:21

                                                          Ksass`Peuk a écrit:

                                                          BorisD a écrit:

                                                          Je les fait heriter d'une classe Capacities pour les stocker dans un std::unique_ptr (que je n'arrive toujours pas a utiliser)

                                                          C'est une solution très simple qui marche bien (même si on peut faire encore plus flexible avec des schémas comme l'Entity Component System). Pour unique_ptr, si tu n'es pas plus précis que ça, ça va être compliqué de t'aider.


                                                          L'entity component system, c'est ce que j'expliquais par

                                                          J'ai écrit:

                                                          A ce moment, on peut aussi le faire heriter d'un Perso,  d'un WeaponContainer, et d'un SpellContainer. Il est possible, aussi, d'utiliser ces strategies qui font l'objet de cette discussion, notamment, pour gerer les IA, comme les loups apprivoises. Si tu pensais a une meilleure solution, j'aimerais bien la connaitre.

                                                          Je sais que je m'explique mal, mais si je me rapelle plus du nom, on va pas se comprendre.:p
                                                          Pour ce qui est des std::unique_ptr, je n'arrive pas a:

                                                          1-Y acceder depuis une classe, sous pretexte que je ne peut pas y acceder comme si c'etait un pointreur membre avec

                                                          MaClasse obj;
                                                          obj.*ptr = 0;

                                                          2-Changer de cible en detruisant l'objet.

                                                          3-Effectuer un transfert de responsabilites vers un autre pointeur nu/unique.

                                                          :o
                                                          Je sais que je meriterait qu'on me reponde RTFM, mais bon, moi, l'anglais, ca va bien quand c'est du niveau college.

                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            26 novembre 2017 à 21:13:56

                                                            Lis la doc !!!

                                                            Tu as une fonction get() qui te renvoie le pointeur, une fonction reset() qui te permet de changer la cible et une fonction release() qui permet d'abandonner la propriété de la cible (au profit d'un autre pointeur intelligent, ca va de soi :D )

                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                            Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                                                              26 novembre 2017 à 21:50:19

                                                              BorisD a écrit:

                                                              1-Y acceder depuis une classe, sous pretexte que je ne peut pas y acceder comme si c'etait un pointreur membre avec

                                                              MaClasse obj;
                                                              obj.*ptr = 0;

                                                              Ben en même temps, ça, même avec un pointeur nu, c'est syntaxiquement faux.

                                                              *(obj.ptr) = 0;

                                                              Ce sera mieux.

                                                              BorisD a écrit:

                                                              2-Changer de cible en detruisant l'objet.

                                                              ptr.reset(std::unique_ptr<int>());

                                                              BorisD a écrit:

                                                              3-Effectuer un transfert de responsabilites vers un autre pointeur nu/unique.

                                                              Reset ou swap, ou encore d'autres possibilités.

                                                              • Partager sur Facebook
                                                              • Partager sur Twitter

                                                              Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

                                                              Classe virtuelle pure en argument

                                                              × 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