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 :

Etendre une série de classe non modifiable/ Héritage virtuel


Sujet :

C++

  1. #1
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut Etendre une série de classe non modifiable/ Héritage virtuel
    Bonjour à tous. J'aimerais connaitre la meilleur façon d'étendre une classe du type :

    class Base (classe abstraite);
    class Derived1 : public Base;
    class Derived2 : public Base;
    class Derived3 : public Base;

    Le problème étant que j'aimerais créer créer une nouvelle classe, similaire à Base mais possédant une fonction virtuelle pure et définir l'implémentation de cette fonction virtuelle pure dans Derived1, Derived2 et Derived3.

    Le problème : je dois créer cette nouvelle classe sans toucher au code de Base, Derived1, Derived2 et Derived3. De plus, il faudrait qu'à chaque extension de Base ma classe s'étende aussi sans y toucher. Et pour finir, il faudrait pouvoir rajouter des classes sans problème.

    On pourrait imaginer un :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class MonBase : public Base
    {
          virtual bool f()=0;
    };
    class MonDerived1 : virtual public MonBase, virtual public Derived1
    {
          virtual bool f(){/*qqch*/}
    };
    ....

    ce système fonctionnerais.

    Cependant, sa me parait mettre beaucoup de code pour pas grand chose et l'héritage virtuelle ne me parait pas super.
    Pour la syntaxe du virtuel, je m'en souvient plus très bien (c'est la première fois que cette possibilité est envisageable) mais si c'est la seule solution je ferais comme sa.


    Merci.

  2. #2
    Membre éprouvé Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Bonjour,
    Je crois que quelques précisions s'imposent, histoire d'être bien sûr qu'on parle de la même chose…

    Citation Envoyé par NoIdea Voir le message
    j'aimerais créer créer une nouvelle classe, similaire à Base
    Qu'est-ce que tu entends exactement par « similaire » ?
    En gros, il faut qu'elle ait exactement le même comportement que « Base », quoiqu'il arrive ?

    Citation Envoyé par NoIdea Voir le message
    De plus, il faudrait qu'à chaque extension de Base ma classe s'étende aussi sans y toucher.
    Qu'est-ce que tu veux dire par « extension » ?
    Des ajouts dans la classe ?
    D'autres classes-filles ?

    Citation Envoyé par NoIdea Voir le message
    Et pour finir, il faudrait pouvoir rajouter des classes sans problème.
    Rajouter des classes…
    Euh, où ça ?

    Pour l'héritage virtuel, direction la FAQ.
    Mais je crains qu'il faille modifier les classes « Derived* ».

  3. #3
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Semblerais que je n'ai pas été assez explicite.
    Je vais donc prendre le cas qui m'intéresse.
    J'utilise la SFML et je ne souhaite pas modifier les sources.
    Cependant, dans la classe Drawable, il me manque une méthode cruciale : virtual bool IsOnDrawable()=0;
    Cette fonction est virtuelle pure et j'ai déjà prévu quel serait son comportement pour les Shape/Sprite/String.

    Mon problème : je ne veux modifier les sources. Je ne peux donc rajouter ces trois fonctions dans les .h correspondants.
    Cependant, il me faudrait qu'à chaque nouvelle version de la SFML (imaginons une nouvelle fonction dans la classe Drawable) soit présente dans ma nouvelle classe sans modifier une seule ligne de code.
    De plus, on doit pouvoir implémenter les classes Shape/Sprite/String avec cette nouvelle fonction. Il faut donc créer ShapeBis, SpriteBis et StringBis. Malheureusement, il faut aussi que c'est trois classe "se mettent à jour automatiquement" quand Shape, Sprite et String sont modifiés. Ou encore, si il s'agit d'un type qu'une autre bibliothèque a créé (qui hérite de Drawable)et qu'on ne veut aussi modifier.

    Ainsi, j'en conclut que DrawableBis doit hériter de Drawable (pour permettre "les mises à jours") ; que toute classe héritant de Drawable à laquelle on veut rajouter cette fonction (appelons la DerivedBis) doit hériter de DrawableBis et de Derived.

    Ainsi, j'obtiens un losange et donc un héritage virtuel.

    Y a t-il une autre solution ?

  4. #4
    Membre averti
    Homme Profil pro
    Analyse système
    Inscrit en
    Novembre 2008
    Messages
    227
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Analyse système
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Novembre 2008
    Messages : 227
    Points : 311
    Points
    311
    Par défaut
    Tu peux envisager d'utiliser des design pattern (le design pattern decorator pourrait répondre à ce que j'ai compris de ton problème.)

  5. #5
    Membre éprouvé Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Ok, je vois.
    C'est à peu près ce que j'avais compris, mais je voulais être sûr.

    Faire de l'héritage multiple pourrait être une solution (enfin disons plutôt une façon de faire…).
    Mais comme je le disais, il faudrait modifier les classes Shape/Sprite/String.
    Donc ce n'est pas possible.

    Je ne pense pas assez aux design pattern, alors qu'ils peuvent rendre de bien grands services, et parfois de manière assez simple…

  6. #6
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Il me semble que le pattern Decorator ne répondent pas à mes besoin : il faudrait modifier Drawable (le faire hérité d'une interface). Cependant, je ne le connaissais pas et répond à un autre besoin que j'avais

    Je vais essayé de faire un shémas en asseyant d'être plus compréhensible.

    Voila les classes SFML, je n'ai le droit de toucher à aucune de ces classes. Il manque une méthode virtuelle pure bool IsOnObject(const Point& P)const dans Drawable et leur implémentation dans les dérivés.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
                          Drawable
                         /     |     \
                     Shape    Sprite  String
    Maintenant, voici les nouvelles classes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
                       DrawableBis
                       /       |       \
                ShapeBis  SpriteBis  StringBis
    Or, DrawableBis doit hérité de Drawable pour avoir toutes les méthodes/propriété de Drawable. On a donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
                                                  Drawable
                                                       |
                                          D R A W A B L E B I S
                                         /             |             \
                                   ShapeBis       SpriteBis      StringBis
    Or, ShapeBis, SpriteBis et StringBis doivient hériter respectivement de Shape, Sprite et String pour avoir toues leurs méthodes/propriétés.

    On obtient donc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
                                     ---------Drawable---------------------
                                     |                 |                  |
                                     |   D R A W A B L E B I S            |
                                     |   /             |             \    |
                                   ShapeBis       SpriteBis      StringBis
    Il nous faut donc de l'héritage virtuel. Cependant, on arrive au résultat voulu.


    Ma question est :

    Existe-il une solution sans héritage virtuel ?

  7. #7
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Si tu ne peux toucher ni à Base, ni à derivedN, cela commence à devenir difficile
    Pourquoi tes extensions doivent forcément être des extensions de Base ? Pourquoi ne pas avoir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // non modifiable :
    class base{};
    class derived : public base{};
     
    // class modifiable :
    class my_extended_base{};
     
    class my_derived : public derived, public my_extended_base
    {};

  8. #8
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Pourquoi tes extensions doivent forcément être des extensions de Base ? Pourquoi ne pas avoir
    (On nommera DrawableBis la classe qui hérite de drawable comme dans mon exemple).
    Supposons ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Fond
    {
    std::vector<DrawableBis*>MesImages;
    bool IsPointInside(const Point& P)const;
    void AddElement(const Drawable& D);
    void Draw(const RendeWindow& W);
    Fond(const Drawable& D);
    ~Fond();
    };
    Comment je fais pour "Draw" si j'ai un vector<my_extended_base*> ?

  9. #9
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Je suis presque persuadé qu'il y a un DP pour ça. En gros, ça pourrait donner quelque chose comme ça :
    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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    #include <iostream>
     
    struct Drawable
    {
        virtual void draw()const=0;
        virtual ~Drawable(){}
    };
    struct widget : public Drawable
    {
        virtual void draw()const
        {
            std::cout<<"draw_widget\n";
        }
    };
     
    struct sprite : public Drawable
    {
        virtual void draw()const
        {
            std::cout<<"draw_sprite\n";
        }
    };
     
    // extension :
    struct DrawableBis
    {
        virtual void meuh()const=0;
        virtual ~DrawableBis(){}
    };
     
    struct widget_cow : public DrawableBis
    {
        virtual void meuh()const
        {
            std::cout<<"widget_meuh\n";
        }
    };
     
    struct sprite_cow : public DrawableBis
    {
        virtual void meuh()const
        {
            std::cout<<"sprite_meuh\n";
        }
    };
     
    struct compound
    {
            virtual Drawable const& get_drawable()const=0;
            virtual DrawableBis const& get_drawable_bis()const=0;
    };
     
    template<class drawable_t_, class drawable_bis_t_>
    struct effective_coumpound : public drawable_t_, public drawable_bis_t_, public compound
    {
        virtual Drawable const& get_drawable()const
        {
            return *this;
        }
        virtual DrawableBis const& get_drawable_bis()const
        {
            return *this;
        }
    };
     
    #include <vector>
    #include <algorithm>
    struct Fond
    {
     
        std::vector<compound*>elements;
        void draw()const
        {// j'ai mis un lambda C++0x pour aller + vite
     
            std::for_each(elements.begin(),elements.end(),[](compound const*p_)
                          {
                              p_->get_drawable().draw();
                          }
            );
        }
        void meuh()const
        {
     
            std::for_each(elements.begin(),elements.end(),[](compound const*p_)
                          {
                              p_->get_drawable_bis().meuh();
                          }
            );
        }
    };
     
    int main()
    {
        effective_coumpound<widget,widget_cow> effective_widget;
        effective_coumpound<sprite,sprite_cow> effective_sprite;
     
        Fond f;
        f.elements.push_back(&effective_widget);
        f.elements.push_back(&effective_sprite);
        f.draw();
        f.meuh();
        return 0;
    }
    [EDIT] avec des bonnes classes traits entre les deux yeux, tu dois pouvoir faire évoluer en // (si c'est ton besoin) les 2 hiérarchies (sprite/sprite_cow, widget/widget_cow and so on) pour déduire l'une à partir de l'autre :
    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
    template<typename drawable_t_>
    struct compound_drawable_trait;
    template<>
    struct compound_drawable_trait<sprite>
    {
        typedef sprite_cow type;
    };
     
    template<>
    struct compound_drawable_trait<widget>
    {
        typedef widget_cow type;
    };
     
    template<class drawable_t_, class drawable_bis_t_>
    struct effective_coumpound : public drawable_t_, public compound_drawable_trait<drawable_t_>::type, public compound
    {

  10. #10
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Merci 3DArchi, j'ai enfin compris ton premier code, je m'attaque à la compréhension du deuxième.
    En tout cas, le premier fait déjà ce que je veux, je crois.
    Merci beaucoup.

  11. #11
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    En fait, j'ai fait un peu ça à la va vite et je pense que ça doit être généralisable.

  12. #12
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Juste une petite question avec new :
    Supposons que j'ai une référence constante qui est passée dans une fonction, et que je veux copier l'objet. De plus, le type de l'objet est dynamique :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void AddElement(const Drawable& D)
    {
    //Je veux créer une copie identique a D, donc même type dynamique :
    Drawable*copie=new Drawable(D)// ? Sa ne marche pas : il créé pour un type statique.
    //Comment faire ?
    }
    Merci.

  13. #13
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Révisez vos classiques comme disait l'autre : Design pattern prototype

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    struct Drawable
    {
    virtual   Drawable*Clone()const=0;
    };
     
    struct derived : public Drawable
    {
    virtual derived *Clone()const{return new derived(*this);}
    };
    void AddElement(const Drawable& D)
    {
    Drawable*copie=D.Clone()
    }

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

Discussions similaires

  1. Comment fournir une base de donnees non modifiable
    Par nadia123456 dans le forum Sécurité
    Réponses: 2
    Dernier message: 29/09/2008, 20h24
  2. Réponses: 2
    Dernier message: 21/07/2008, 14h26
  3. Réponses: 1
    Dernier message: 18/02/2008, 12h55
  4. Héritage d'une classe MFC et d'une classe non MFC
    Par Etienne Paquette dans le forum MFC
    Réponses: 7
    Dernier message: 04/12/2007, 20h19
  5. [Débutant] Filtrer une zone de liste non modifiable
    Par jeanchcom dans le forum Access
    Réponses: 7
    Dernier message: 08/08/2006, 09h48

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