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 :

C++ : Heritage multiple mais de même base.


Sujet :

C++

  1. #21
    Membre éclairé
    Inscrit en
    Septembre 2003
    Messages
    391
    Détails du profil
    Informations forums :
    Inscription : Septembre 2003
    Messages : 391
    Par défaut
    Citation Envoyé par Mat007
    vont devoir d'une façon ou d'une autre obtenir (voire conserver) une référence sur une instance de cette classe.
    Donc si j'ai bien compris (et je te jure que je fais un effort hein)
    prenons le bon exemple de nicroman
    le CWapon de l'exemple, on le laisse deriver de CCollectableObject uniquement.
    Mais pour lui ajouter la caracteristique "animé", on crée une instance d'un CAnimated que l'on met en donnée membre ? (pour en garder une reference)
    C'est bien ca ?


    Citation Envoyé par Mat007
    Si tu aggrèges c'est un peu comme si tu mettais une articulation entre deux objets : ça peut bouger, ça se démonte facilement, tu peux intercaler d'autres objets entre les deux tant que le mécanisme de fixation est compatible, etc..
    Si tu dérives tu soudes les deux objets ensemble.
    c'est compliquer les metaphore là, il me faut du concret si tu veux que je comprenne

  2. #22
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    Si si elle est très bonne tu vas comprendre!

    Tu as (dans la vraie vie, pas dans ton IDE) deux objets A et B soudés l'un à l'autre. Imaginons que tu veuilles rajouter un petit objet à l'extrémité de B qui est collée à A, tu fais comment? Tu peux pas c'est soudé.
    Le dessin qui va avec : (le X est la soudure)
    <--------X------------>
    B A
    Ca c'est le lien qu'il y a entre une classe mère et sa dérivée.

    On voit bien que tu ne peux rien mettre. Par contre, si A et B sont liés par un mécanisme déformable, souple, etc ... on compare donc ici à la composition, cela donne plutot cela :
    <-------->O<------------>
    B A
    O désigne le mécanisme très souple qu'on peut détacher, remettre.
    Donc si on veut par exemple rajouter un bout C à l'extrémité droite de B, on peut, cela donne ceci :
    <--------><-->O<------------>
    B C A
    De plus A n'y verra que du feu car tout ce que A peut voir c'est le mécanisme de liaison flexible qui est en fait la composition .

    Ca va mieux ?

  3. #23
    Membre éclairé
    Inscrit en
    Septembre 2003
    Messages
    391
    Détails du profil
    Informations forums :
    Inscription : Septembre 2003
    Messages : 391
    Par défaut
    Citation Envoyé par Mat007
    Par exemple il leur suffit de savoir qu'il existe une méthode MoveTo( x, y ) et c'est tout.
    juste une remarque qui n'a peut être pas d'importance,
    non ma classe n'as pas de MoveTo(), on ne le dit pas ou elle doit aller. c'est elle qui decide de son mouvement, elle a juste une methode depl(), un "ticks", on lui envois ce "deplace toi" quand c'est a son tour (boucle principal du jeu).

    D'ailleur, moi mes x et y sont encapsulés justement, il n'est pas question que ca soit géré en dehors... qui parlait de "bug de conception" ?
    bon c'est bas ce que je viens de dire, tu ne connais pas mon projet, tu ne pouvais pas savoir.
    Par contre j'attends de voir un exemple concret avec le CWapon et cette histoire d'agregation, je suis vraiment interessé.

  4. #24
    Membre éclairé
    Inscrit en
    Septembre 2003
    Messages
    391
    Détails du profil
    Informations forums :
    Inscription : Septembre 2003
    Messages : 391
    Par défaut
    Citation Envoyé par Alp
    Si si elle est très bonne tu vas comprendre!
    Ca va mieux ?
    Ben... pour te montrer ce que je comprends (pas).. disons que ton C est un bout de code, bon ben je ne vois pas en quoi avec une classe dérivé tu ne peut pas rajouter une methode (C) dans la classe de base ?
    Bon, et puis si C n'est pas du code mais des données, ben c'est pareil, je ne vois pas de soucis.

    tu vois avec les metaphore c'est pas gagné.

    Mais je suis friand d'exemple, celui nicroman est super. i la bien decrit ce qu'il ne fallais PAS faire, mais c'est vague pour moi sur ce qu'il faut faire...
    et donc j'ai juste une question a ce propos que je recopie ici :
    le CWapon de l'exemple, on le laisse deriver de CCollectableObject uniquement.
    Mais pour lui ajouter la caracteristique "animé", on crée une instance d'un CAnimated que l'on met en donnée membre ? (pour en garder une reference)
    C'est bien ca ?

  5. #25
    Expert confirmé

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

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

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par hpfx
    Donc si j'ai bien compris (et je te jure que je fais un effort hein)
    prenons le bon exemple de nicroman
    le CWapon de l'exemple, on le laisse deriver de CCollectableObject uniquement.
    Mais pour lui ajouter la caracteristique "animé", on crée une instance d'un CAnimated que l'on met en donnée membre ? (pour en garder une reference)
    C'est bien ca ?
    Absoluement....

    Après il y aura toujours des cas alambiqués comme Carré - Losange - Rectangle - Parrallelogramme....
    Un Carré est un Losange et un Rectangle
    Un Losange est un parallelogramme
    Un Rectangle est un parrallelogramme

  6. #26
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    Non C n'est ni une donnée ni une fonction.
    A et B ont une relation. Chez toi c'est l'héritage, nous on te conseille la composition.
    Si on veut mettre une classe C entre A et B dans la relation, ca serait dur de le faire par l'héritage, enfin en tout cas tu vois qu'il faudra modifier pas mal de code et ça restera _rigide_ . Enfin, je laisse nicroman t'expliquer alors

  7. #27
    Membre éclairé
    Inscrit en
    Septembre 2003
    Messages
    391
    Détails du profil
    Informations forums :
    Inscription : Septembre 2003
    Messages : 391
    Par défaut
    Citation Envoyé par nicroman
    Absoluement....
    Ok, merci baucoups.

    Bon, alors je resume.
    Là ou moi j'aurai crée une classe supplementaire CAnimWapon qui aurait dérivé à la fois de CAnimated et de CWapon (donc on se retrouve en diaman).
    Et bien vous, vous créez un membre de CWapon, disons mAnim.

    ok.
    c'est plus simple a maintenir ? sans doute.
    mais par contre, moi j'ai quand même un probleme :
    1er probleme.
    pour faire reference a mon projet, disons que j'ai des Wapon qui sont animated et des Wapon qui ne le sont pas (des enemis qui bougent et qui ne bouge pas, des plantes carnivores si vous preferez)

    disons qu'il existe une methode draw() (ou render() peu importe le nom qu'on lui donne) cette fonction est en charge de dessiner l'objet.
    moi de mon coté j'appelle p->draw() et hop la magic du C++ (le polymorphisme?) fait que le bon draw est appellé (celu ide cWapon ou celui de CanimWapon)
    mais vous avec votre systeme ?
    vous appeller p->draw(); de CWapon...
    dans lequel vous avez un IF ou un SWITCH qui en fonction du type d'objet (ha oui tiens un membre supplementaire) et vous faites :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    CWapon::draw()
    {
    if (mIsAnimated) mAnim.draw();
    else
     {
     // le draw dans le cas ou c'est pas animé
     }
    }
    moi je ne trouve pas celà bien.
    d'ailleur je cite ici : http://www.parashift.com/c++-faq-lit....html#faq-25.4
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Use inheritance only if doing so will remove if / switch statements from the caller code
    que je traduit par : l'heritage c'est pas mal pour eviter des if/switch.. (c'est logique car c'est une "specialisation" on le rends plus précit, plus specialisé, il est animé, s'il fallait gerer toutes les specialité dans une seule classe on aurait une tone de If/switch)

    2eme probleme.
    il y a plein de parametre qui faudra sans cesse synchroniser entre la classe CWapon et ses "agragation" (objet membre)
    de temps en temps il faudra lui dire que ses coordonnées ont changé (peu importe comment si c'est un objet a part ou si c'est 2 variable x et y)
    i lfaudra :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    mAnim.x=x;
    mAnim.y=y;
    // ou alors, peu importe
    mAnim.setCoord(mCood);
    mais il peu y avoir d'autre parametre (cycle de vie de l'objet par exemple...)
    Bref des données qui existe dans les classe CAnim et CWapon et qu'il ont en commun (que se soit par derivation d'une classe de base ou pas!) CAnim a besoin de coordonnées pour animer des objet qui sont instancié directement (est-ce un bon exemple?) et Cwapon aussi...
    j'utilise le cycle de vie (status=dead) par exemple pour ne pas faire de rendu grapfique si l'objet n'existe plus...

    avec la derivation en diaman, non seulement il n'y a pas besoin de les synchroniser, mais en plus il n'y a pas de redondance, car il n'y a qu'une seule variable !


    voilà.
    alors, qu'en pensez vous ? est-ce que je me plante ? est-ce bien celà l'agregation ? les probleme que je vois sont ils contournablent, sont'ils acceptablent pour vous ? ou n'existent pas car vous faites autrement ?

  8. #28
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Citation Envoyé par hpfx
    dans lequel vous avez un IF ou un SWITCH qui en fonction du type d'objet (ha oui tiens un membre supplementaire) et vous faites :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    CWapon::draw()
    {
    if (mIsAnimated) mAnim.draw();
    else
     {
     // le draw dans le cas ou c'est pas animé
     }
    }
    moi je ne trouve pas celà bien.
    Tu fais bien
    En fait CWeapon::draw se contenterait de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    CWapon::draw()
    {
      mAnim.draw();
    }
    Et c'est le CAnimation qui se débrouillerait.
    Du coup on voit bien à quel niveau se situe la souplesse : il suffit de construire CWeapon en lui passant une différente implémentation de CAnimation pour, sans changer autre chose, modifier son comportement vis à vis du reste du système.

    Citation Envoyé par hpfx
    il y a plein de parametre qui faudra sans cesse synchroniser entre la classe CWapon et ses "agragation" (objet membre)
    de temps en temps il faudra lui dire que ses coordonnées ont changé (peu importe comment si c'est un objet a part ou si c'est 2 variable x et y)
    i lfaudra :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    mAnim.x=x;
    mAnim.y=y;
    // ou alors, peu importe
    mAnim.setCoord(mCood);
    Si tout le monde a une référence sur le même objet Coordinate il sera mis à jour pour tout le monde à la fois.
    Si c'est une notification de mise à jour qu'il faut (pour déclencher des traitements uniquement en cas de modification) il faudra sans doute s'intercaler quelque part dans l'appel de méthodes qui va mener à la modification des données x et y : c'est quand même plus facile avec un 'setCoord'.
    Et de nouveau on voit que l'aggrégation apporte une solution plus souple en permettant de plus facilement intercaler des objets.
    L'alternative est de dériver pour réimplémenter la méthode 'setCoord', y écrire un traitement spécifique, puis rappeler la 'vraie' méthode 'setCoord'.
    Oui mais c'est laquelle la 'vraie' méthode 'setCoord' dans une hiérarchie avec de l'héritage multiple partout ?

    MAT.

  9. #29
    Expert confirmé

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

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

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    Bon... je vais essayer d'extraire une classe de mon moteur pour prendre un exemple concret:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
    class Resource : public SmartData
    {
    protected:
       virtual  void load(inputstream is)
       {
            /* ici on va 'charger' le renderable. Donc: lire la classe, instancier un objet de cette classe là, et 'charger' le renderable a partir d'autre resources. */
       }
    };
     
    class Object : public Resource
    {
    private:
     
    public:
       /* n'importe quoi nécessaire à la gestion des objets, genre getId(), ... */
     
    protected:
       virtual  void loadState(inputstream id)
       {
            /* ici on récupère d'un save-game l'état de l'objet au moment du save. */
       }
     
       virtual  void saveState(outputstream id)
       {
            /* ici on serialise l'état de l'objet. */
       }
    };
     
     
    class ObjectBehavior : public Resource
    {
        /* histoire de récupérer un objet à partir du behavior. */
        Object*   getObject();
    };
     
    class PhysicalBehavior : public ObjectBehavior
    {
        /* abstraction du moteur physique. permet aussi de récupérer la position/vitesse de l'objet à tout moment. */
        WorldPosition    getPosition();
        WorldSpeed      getSpeed();
    };
     
    class RenderingBehavior : public ObjectBehavior
    {
        /* abstraction du moteur graphique. permet aussi de dessiner l'objet (méthode "Draw()"). */
         void    Draw();
    };
    ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     
     
    class WorldObject : public Object
    {
       /* virtuellement tous les objets peuvent être 'renderable'. Le lien vers renderable se fait au load. */
        SmartPtr<RenderingBehavior>   mRendering;
        /* Un pointeur vers un 'physicalObject'. Le PhysicalObject. */
        SmartPtr<PhysicalBehavior>   mPhysics;
    public:
        inline PhysicalBehavior*  getPhysicalBehavior() const
        { return mPhysics; }
     
       inline RenderingBehavior*  getRenderingBehavior() const
       { return mRendering; }
     
    protected:
       virtual void load()
        { /* chargement du rendering-behavior et du physical-behavior des resources. */ }
    };
     
    class CollectableItem: public WorldObject
    {
        SmartPtr<InventoryBehavior>   mInventory;
    public:
        inline InventoryBehavior*  getInventoryBehavior() const;
        { return mInventory; }
     
    protected:
       virtual void load()
        { /* chargement du inventory-behavior des resources. */ }
    };
     
     
    class EquipableItem : public CollectableItem
    {
        SmartPtr<CharacterBehavior>   mCharBehavior;
    public:
        inline CharacterBehavior*   getCharacterBehavior() const
        { return mCharBehavior; }
    };
     
    class UsableItem : public EquipableItem 
    {
        SmartPtr<SkillUsageBehavior>    mSkillUsage;
    public:
        inline SkillUsageBehavior*  getSkillUsageBehavior() const
        { return mSkillUsage; }
    };
     
    ...

    Ca c'est la partie 'world management'... Le truc qui va gérer la durée de vie des objets....

    Maintenant, on veut dessiner des objets... c'est facile (pseudocode):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    foreach Object obj in list
        if (obj.getRenderingBehavior())
            obj.getRenderingBehavior().draw();
    On veut les afficher dans l'inventaire ? L'inventaire est composé de CollectableItems:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    foreach CollectableItem it in list
        if (it.getInventoryBehavior())
            it.getInventoryBehavior().displayImage()
    Maintenant je peux tres bien faire en sorte qu'une "porte" spéciale du jeu puisse être mise dans l'inventaire sans toucher un seul bout de code ! Il suffit que je lui associe l' inventory-behavior adapté.

    Ainsi, on peut changer simplement par les resources comment une armure va influer sur le personnage. Voir animer l'armure si on a envie....

    Le meileur exemple étant sur les miroirs / doorway / portals.

    Un 'portal' est un objet spécial qui permet de changer de zone quand on le franchit.
    Un miroir est un simple objet du monde.
    Et pourtant, les deux utilisent le même rendering-behavior: PortalRendering qui permet de voir une autre zone (ou la même) sous un autre angle (ou le même).

Discussions similaires

  1. Réponses: 1
    Dernier message: 27/02/2015, 10h32
  2. Services multiple pour une même base
    Par tibal dans le forum Administration
    Réponses: 5
    Dernier message: 17/04/2009, 09h27
  3. [Debutant]Insertion nulle mais '' dans la base
    Par Tchinkatchuk dans le forum PostgreSQL
    Réponses: 10
    Dernier message: 18/04/2005, 10h58
  4. Heritage accès aux membres de bases
    Par MAGNUM_HEAD dans le forum C++
    Réponses: 1
    Dernier message: 16/11/2004, 17h41
  5. [Kylix] heritage multiple et interfaces :(
    Par le_barbu dans le forum EDI
    Réponses: 4
    Dernier message: 26/01/2004, 20h30

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