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

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

 C++ Discussion :

Problème lié à l'héritage


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2017
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2017
    Messages : 6
    Par défaut Problème lié à l'héritage
    Bonjour,

    J'ai un problème lié à l'héritage et je ne sais pas comment le résoudre.

    J'ai deux classes Goomba et Koopa qui héritent chacune de ma classe Entity. Ma classe Zone contient comme attribut une collection hétérogène d'Entity contenant donc des pointeurs vers des instances de Goomba et de Koopa. J'ai ajouté une méthode changerOrientation() à la classe Koopa qui n'est pas dans Entity et j'aimerais pouvoir l'utiliser depuis ma classe Zone. Je ne vois pas comment faire.

    Mon attribut(La collection hétérogène) dans la classe Zone
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    std::deque<Entity*> m_entites;
    La classe Koopa :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    #ifndef KOOPA_H_INCLUDED
    #define KOOPA_H_INCLUDED
     
    #include "Entity.h"
     
    class Koopa : public Entity
    {
    public:
        Koopa(float x, float y);
        void seDeplacer();//vp
        void sAnimer();//vp
     
        void changerOrientation();
     
    private:
        bool m_orientationDroite;//true s'il regarde à droite false sinon
     
    };
     
    #endif // KOOPA_H_INCLUDED
    La fonction dans Zone censée utiliser changerOrientation()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    void Zone::horsZone()
    {
        unsigned int t(m_entites.size()), i;
        for(i = 0; i<t; ++i)
        {
            if(m_entites[i]->getPosition().y > m_origine.y + m_hauteur)//si on est en dessous de la zone
            {
                rearanger(i);
            }
            else if(m_entites[i]->getPosition().x < m_origine.x || m_entites[i]->getPosition().x > m_origine.x + m_largeur)//si on est à gauche ou à droite de la zone
            {
                if (typeid(*m_entites[i]) == typeid(Koopa))
                {
                    m_entites[i]->changerOrientation();
     
                }
            }
        }
    }

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Si tu en arrives à coder des choses du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (typeid(*m_entites[i]) == typeid(Koopa))
    c'est que tu as un problème de conception.

    La bonne manière de faire est d'ajouter changerOrientation() comme méthode virtuelle à Entity, avec un corps vide. Tu la redéfinis dans Koopa.

    Si la présence de cette fonction n'a vraiment aucun sens pour les types autres que Koopa, tu peux créer à la place une autre méthode virtuelle, au nom assez générique ( du genre postProcess()), dont la redéfinition dans Koopa appellera changerOrientation().

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2017
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2017
    Messages : 6
    Par défaut
    Ok merci je vais mettre la méthode changerOrientation() dans ma classe Entity. Je trouve ça juste dommage et "encombrant" de rajouter une méthode avec un corps vide mais bon s'il n'y a pas d'autres solutions. Merci encore.

    Ducoup deuxième problème : Comment faire pour savoir vers quel type pointe mes pointeurs dans m_entites sans utiliser typeid ? Par exemple, si c'est un Goomba, je détruis l'Entity, et si c'est un Koopa, je détruis l'Entity et la remplace par une Carapace (héritant de Entity).

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Citation Envoyé par Rhaegar() Voir le message
    Du coup deuxième problème : Comment faire pour savoir vers quel type pointe mes pointeurs dans m_entites sans utiliser typeid ? Par exemple, si c'est un Goomba, je détruis l'Entity, et si c'est un Koopa, je détruis l'Entity et la remplace par une Carapace (héritant de Entity).
    Tu ne devrais pas être amené à te poser cette question. Si c'est le cas, c'est que tu as un problème de conception.

    D'après ce que tu exposes,je pense que la première question à se poser est : ce vecteur a-t-il un sens ? Est-il nécessaire ?

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2017
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2017
    Messages : 6
    Par défaut
    Il a un sens dans le fait que souvent, toutes les Entity seront traitées de la même façon. Par exemple, lorsque je détruis Zone, le destructeur détruit toutes les Entity pointées par m_entites via une seule boucle pour. De même, la méthode animation de Zone va appeler la méthode animation de chaque Entity par une boucle pour.

    Cependant, j'ai parfois besoin d'effectuer différentes choses en fonction du type d'Entity(Goomba ou Koopa)

    Sinon je pourrais faire différents vecteur pour chaque type d'Entity mais je trouve dans ce cas l'utilisation des collections hétérogènes très limitée.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,
    Citation Envoyé par Rhaegar() Voir le message
    Il a un sens dans le fait que souvent, toutes les Entity seront traitées de la même façon. Par exemple, lorsque je détruis Zone, le destructeur détruit toutes les Entity pointées par m_entites via une seule boucle pour. De même, la méthode animation de Zone va appeler la méthode animation de chaque Entity par une boucle pour.

    Cependant, j'ai parfois besoin d'effectuer différentes choses en fonction du type d'Entity(Goomba ou Koopa)

    Sinon je pourrais faire différents vecteur pour chaque type d'Entity mais je trouve dans ce cas l'utilisation des collections hétérogènes très limitée.
    Ca, j'ai envie de dire que c'est TON point de vue...

    Mais ce que oodini tente de t'expliquer, c'est qu'il se peut (et c'est même très probable) que ton problème est sans doute beaucoup plus profond et trouve son origine dans ... le fait de décider que Koopa et que Goomba en viennent à hériter de Entity.

    Car l'héritage est la relation la plus forte qui puisse exister entre deux classes car elle représente littéralement le fait que n'importe quelle instance de la classe dérivée peut être considérée comme étant une instance de la classe de base.

    Il doit donc respecter des règles strictes qui sont en l'espèce imposées par le LSP.

    Je ne vais pas dire (je ne connais pas assez ton projet pour en venir à cette conclusion) que tu as commis une erreur de conception en décidant de faire hériter Goomba ou Koopa de Entity. Il se peut au demeurant que cette décision soit tout à fait sensée et qu'elle respecte intégralement le LSP.

    Mais, une chose est sure : si tu as été "assez bête" (même si c'est par nécessité), pour en arriver, à un moment ou à un autre, à considérer que tous tes Goompa et / ou que tous tes Koopa sont des Entity, tu ne peux appeler que les comportements issus de Entity, à l'exclusion de tout autre et tu ne peux surtout pas commencer à entrer dans une logique par laquelle tu essayerais de déterminer si ton entité est un Goompa ou un Koopa avant de la transtyper dans l'un ou dans l'autre afin de pouvoir faire appel aux comportements spécifiques de ce genre de donnée.

    Il existe en effet un principe d'or nommé OCP pour Open Close Principle, qui dit qu'un code doit être "ouvert aux évolutions" mais "fermé aux modifications".

    Si tu commences à écrire un code qui ressemble peu ou prou à quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    if(entity->type() == Koopa){
        dynamic_cast<Koopa>(entity)->trucSpecificAKoopa();
    }else if(entity->type() == Goompa){
        dynamic_cast<Goompa>(entity)->trucSpecificAGoompa();
    } else if(entity->type() == MachinBrol){
        dynamic_cast<MachinBrol>(entity)->trucSpecificAMachinBrol();
    }
    tu écris du code qui ne respecte pas l'OCP, et le résultat sera sans appel: dans "quelque mois" tu voudra rajouter une classe supplémentaire (mettons Truc) à ta hiérarchie, et, pour que cette classe supplémentaire soit prise en compte, tu devrais modifier tous les endroits du code dans lequel ce genre de logique est mis en oeuvre pour y rajouter les lignes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    else if(entity->type()== Truc){
        dynamic_cast<Truc>(entity)->trucSpecificATruc();
    }
    La loi de finagle aidant, tu penseras à modifier un des endroits en question, peut-être deux, mais tu en oublieras bon nombre d'autres.

    Si tu veux trouver une solution correcte à ton problème, les mots clés à rechercher sont virtualité des fonctions et double dispatch.

    L'exemple classique de mise en oeuvre du double dispatch que l'on propose régulièrement porte le nom du patron de conception visiteur.
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. problème avec mcd héritage
    Par minooo dans le forum Schéma
    Réponses: 4
    Dernier message: 16/01/2008, 09h57
  2. problème sur un héritage de combobox
    Par azräel dans le forum MFC
    Réponses: 4
    Dernier message: 27/06/2007, 10h17
  3. Problème concernant l'héritage
    Par Premium dans le forum C++
    Réponses: 3
    Dernier message: 17/03/2007, 02h15
  4. [VC++] Problème avec un héritage
    Par Freakazoid dans le forum Visual C++
    Réponses: 7
    Dernier message: 28/11/2005, 08h35
  5. [DEBUTANT] Probléme avec l'héritage
    Par BRAUKRIS dans le forum Langage
    Réponses: 7
    Dernier message: 16/09/2005, 20h22

Partager

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