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 :

probleme de compréhension de la composition


Sujet :

C++

  1. #1
    Membre habitué Avatar de bringer
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Points : 137
    Points
    137
    Par défaut probleme de compréhension de la composition
    Bonjour à tous et bonnes vacances,

    Je travail actuellement avec le livre de B. Stroustrup "principe et pratique avec C++" (Excellent au demeurant à mon humble avis).
    Je suis au chapitre 14 où il est question d'héritage, classe abstraite, fonctions virtuelles ...
    Ce chapitre travail avec une abstraction de la bibliothèque FLTK avec des classes fournies par le livre (comme Shape, Line, Circle, Rectangle...)
    Un des exercice demande de dériver la classe Circle afin de faire une classe Smiley composée de 2 yeux et une bouche eux meme des circles.

    Ma relexion m'a amenée à me dire que un Smiley est une sorte de Circle donc dérivation, mais qu'un Smiley a des yeux donc composition de Eyes dans la classe Smiley sous la forme.

    yeux étant initialisé dans la liste d'initialisation du constructeur de Smiley.
    J'ai fournis dans Smiley une fonction de modification de l'épaisseur des lignes des yeux et dans Eyes la fonction d'accès adéquate (public).

    Mon problèmes est que si je veux changer l'épaisseur ou tout autre caractéristique des yeux à partir de mon objet Smiley, ça ne fonctionne pas.
    Par contre, si je le fais en créant une instance directe de Eyes dans le main(), là ça fonctionne sans problème.

    Je ne comprend pas pourquoi.
    Merci d'avance.

  2. #2
    Membre habitué Avatar de bringer
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Points : 137
    Points
    137
    Par défaut
    Petite précision,

    Si je change le format de ligne d'un Smiley, alors tout le Smiley (y compris les yeux) subit le changement.
    Hors, je souhaiterais certainement pouvoir contrôler indépendamment les yeux.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 59
    Points : 57
    Points
    57
    Par défaut
    Bonjour, j'ai du mal a m'imaginer le truc, plus de code serai le bienvenu (montre nous le code de tes class en precisant ce qui marche ou pas stp).

  4. #4
    Membre habitué Avatar de bringer
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Points : 137
    Points
    137
    Par défaut
    Evidemment Vodsky, ce n'est pas super clair mon histoire. Voila un peu de code.

    Eyes.h
    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
     
    #include "Graph.h"
    class Eyes : public Circle {
      public:
        Eyes(Point p, int r);
        void draw_lines() const; //fonction virtuelle fournies par Circle
        void liner(int epaisseur); // pour modifier l'épaisseur des traits
     
      private:
        Point init; // stocke une paire de coordonnée x,y
        int radius;
        int width;
        Point l_eye;
        Point r_eye;
        int r_leye;
        int r_reye;
    };
    Eyes.cpp
    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
    #include "Eyes.h"
    Eyes::Eyes(Point p, int r):
      Circle(p,r), init(p), radius(r), r_leye(10), r_reye(10) {
    ...
    }
     
    void Eyes::draw_lines() const{
      Circle left_eye(l_eye, r_leye);
      left_eye.draw_lines();
      Circle right_eye(r_eye, r_reye);
      right_eye.draw_lines();
    }
     
    void Eyes::liner(int epaisseur)
    // dessine des yeux avec une epaisseur
    {
      set_style(Line_style(Line_style::solid, epaisseur));
    }
    Maintenant Smiley.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include "Eyes.h"
    class Smiley : public Circle {
      public:
        Smiley(Point p, int r);
        void draw_lines() const; / meme fonct virtuelle que pour Eyes
        void eye_line(int); //fonction d'accès à Eyes::liner(int)
      private:
        Point init;
        int radius;
        Eyes e; // mon objet Eyes (composition)
    };
    et Smiley.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include "Smiley.h"
    Smiley::Smiley(Point p, int r):
      e(p,r), Circle(p, r), init(p), radius(r){
    ....
    }
     
    void Smiley::draw_lines() const{
      Circle::draw_lines();
      e.draw_lines();
    }
     
    void Smiley::eye_line(int epaisseur) {
      e.liner(epaisseur);
    }
    enfin le main()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #include "Smiley.h"
     int main() {
    ...
          Smiley s(Point(150,150),50);
          s.eye_line(2);
    ...
    }
    Voila. aucune erreur de compilation ou autre, mais rien ne se passe à l'exécution. Par contre, si j'essaie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main() {
    ...
          Eyes e(Point(300,150),50);
          e.liner(4);
    ...
    Dans ce cas, l'épaisseur est correctement modifiée.

    Et enfin, si j'essaie
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include "Smiley.h"
     int main() {
    ...
          Smiley s(Point(150,150),50);
          s.set_style(Line_style(Line_style::solid, 2));// fonction de modification 
                                           //du type de ligne et épaisseur fournie par
    //Circle dérivée de Shape.
    ...
    }
    Dans ce cas, toute les lignes passent à une épaisseur de 2 y compris mon objet Eyes. Mais ce n'est pas le résultat attendu. De plus, mon objet Smiley n'est pas censé connaitre ce genre de détail.

    J'espère que c'est un peu plus clair maintenant.
    D'avance merci.

  5. #5
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Tu est parti sur la bonne base:
    • Smiley EST bel et bien UN circle, donc héritage, et
    • Smiley A bel et bien DES yeux, donc composition (attention: il en a sans doute deux, susceptibles d'évoluer de manière distinctes )
    Par contre, maintenant, il s'agit d'aller un peu plus loin en s'intéressant aux comportement que tu souhaite voir adoptés par ton Smiley... :
    Il y a certains comportements qui doivent être adaptés ( draw qui doit, en plus de tracer le cercle, tracer les yeux ) mais il y a aussi sans doute une série de comportements qui sont propres au smileys.

    Tu peux, par exemple, estimer intéressant d'avoir un comportement qui... modifie le style des yeux (l'utilisateur n'ayant pas besoin de savoir que l'on manipule justement des yeux ), et permettant de choisir quel est l'oeil dont on veut modifier le style.

    Cela pourrait prendre une forme proche de
    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
    /* une petite énumération qui nous facilite la tache :D */
    enum RightOrLeft
    {
        Right,
        Left,
        Both
    };
    class Smiley: public Circle 
    {
        public:
            void modifyEyesStyle ( Style const & s, RightOrLeft rol )
            {
                switch(rol)
                {
                    case Right : 
                        r_eye.setStyle(s);
                        break;
                    case Left :
                        l_eye.setStyle(s);
                        break;
                    case Both :
                        r_eye.setStyle(s);
                        l_eye.setStyle(s);
                        break;
                }
            }
      /* as before */
    }
    (n'oublie pas de définir le comportement "setStyle" pour ta classe Eye )Tu pourrais aussi prévoir des comportements tels que closeEye(RightOrLeft), openEye(RightOrLeft), bigEye(RightOrLeft), ou que sais-je qui auront pour effet de... modifier la forme prise par les yeux, selon le même principe.

    Le tout pourrait alors s'utiliser sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    int main()
    {
         Smiley smile;
         smile.modifyEyesStyle(Style(/*...*/, Right); // modifie le style de l'oeil
                                                      // droit uniquement
         smile.modifyEyesStyle(Style(/*...*/, Both); // modifie le style des 
                                                     // deux yeux
    }
    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

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 59
    Points : 57
    Points
    57
    Par défaut
    Bonjour,
    concernant ton problème initial je ne vois rien, j'aimerai bien tester ton code pour tentez de debuguer, tu pourrais en faire un .rar ou .zip? (évite tar.gz pls )

  7. #7
    Membre habitué Avatar de bringer
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Points : 137
    Points
    137
    Par défaut
    Merci à tous les 2 de vos réponses.

    pour koala01 :
    je ne vois pas bien la différence avec ce que j'avais déjà fait (hors mis le contrôle dissocié des yeux, mais là n'est pas mon souci). J'ai quand meme testé le code et rien de plus ne se passe.

    En fait, on dirait que le fait que Smiley et Eyes soient dérivés de Circle est gênant. Le prog réagit comme si ce n'était qu'un seul et même objet empêchant ainsi le contrôle dissocié. De plus, le fait de passé par Smiley pour modifier Eyes (logique au demeurant), semble perturber le prog. Aucune mise à jour "visuelle" ne se fait.

    Pour Vodsky :
    Ok je te fait un ZIP complet des classes dans l'après midi. Il te faudra par contre installer la lib FLTK depuis FLTK.org version 1.1.
    Le prog se compile par un makefile fourni qui créé une lib statique nommée libbookkgui.a.
    ensuite le link se fait : g++ -lfltk -lfltk_image -o monexe -L. -lbookgui

    merci de votre aide, je continu à chercher (ça fait 4 jours que je triture le probleme, alors un 2 plus ne fait plus grand chose), mais ça énerve "*p#§&?n".

    bringer

  8. #8
    Membre habitué Avatar de bringer
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Points : 137
    Points
    137
    Par défaut
    voici le ZIP du projet
    Fichiers attachés Fichiers attachés

  9. #9
    Membre habitué Avatar de bringer
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Points : 137
    Points
    137
    Par défaut
    Petite réflexion :

    Je suis parti sur l'idée que Eyes est dérivé de Circle parce que je dessine les yeux avec 2 cercles.
    N'est-ce pas une erreur ?
    On pourrait dire également que Eyes (je gère les 2 yeux en même temps) est une classe dérivée de Shape (classe abstraite de base) et que Eyes a 2 cercles pour former les yeux.
    Auquel cas, la définition de Eyes changerait en quel que chose comme :
    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
     
    class Eyes : public Shape {
      public:
        Eyes(Point p, int r);
        void draw_lines() const;
        void set_eyes_width(const int);
        void set_eyes_color(const Color&);
        ~Eyes() {delete left_eye; delete right_eye;}
     
      private:
        Point init;
        int radius;
        int width;
        Circle* left_eye;
        Circle* right_eye;
      Point l_eye;
        Point r_eye;
        int r_leye;
        int r_reye;
     
      };
    Bon, j'ai essayé, mais pour tout dire, ça ne fonctionne pas plus. Pourtant, est-ce que cela ne pourrait pas être une idée acceptable ?

    De plus, est-il possible de se passer des pointeurs (maitrise pas le sujet pour le moment...) ?

    bringer

  10. #10
    Membre averti
    Homme Profil pro
    Inscrit en
    Avril 2002
    Messages
    290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2002
    Messages : 290
    Points : 325
    Points
    325
    Par défaut
    Bonjour,

    Oui Eye est un cercle, mais Eyes non
    Eyes est l'association de deux cercles, ce n'est pas un cercle.

  11. #11
    Membre habitué Avatar de bringer
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Points : 137
    Points
    137
    Par défaut
    bonjour,

    je reviens vers vous suite à vos conseils, j'ai pu avancer.
    Il me reste quant meme un problème de compréhension assez sévères.

    Je créé 2 classes Striped_rectangle qui dérive de Rectangle et Stripeds qui dérive de Lines qui est capable d'envelopper dans un objets plusieurs lignes.
    Rectangle et Lines sont fournir par la "bibliothèque graphique" du livre (cf 1er article)

    Comme je souhaite pouvoir faire des formes hachurées horizontalement pour le moment, je créé une aggrégation avec un pointeur de Striped dans Striped_rectangle et je joint quelques fonctions de modifications (espacement des hachures, épaisseurs des hachures et couleur).

    La où je ne suis plus, c'est que quand j'appel ces services pour le Striped_rectangle, rien ne se passe, par exemple, la couleur des hachures ne change pas.
    Mais si je créé un objet Striped dans mon main() pour tester, là, toutes mes fonctions de modification fonctionnent bien.

    Je n'arrive pas à comprendre pourquoi. Je joins un ZIP des fichiers pour ceux qui veulent jeter un oeil.

    merci d'avance. bringer
    Fichiers attachés Fichiers attachés

  12. #12
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Cela aurait été pas mal si tu avais pensé à placer la définition de ta classe Rectangle avec les sources, mais bon...

    Je crois que tu va chercher un héritage là où il n'y a pas forcément besoin d'en avoir un...

    La classe "Stripped_rectangle" n'apporte rien de plus que ce que la classe Rectangle ne peut apporter car la seule chose qui change, c'est la manière dont le rectangle est rempli.

    Mais il n'est pas de la responsabilité du rectangle de déterminer la manière dont il est rempli : ce devrait être de la responsabilité... d'une classe particulière (Filler ) que l'on transmettrait aux différentes formes qui l'utiliseraient pour effectuer leur rempliçage.

    Le fait est que, pour l'instant, tu t'attaque à la capacité des formes de se remplire de manière hachurées (horizontalement), mais que tu ne va sans doute pas tarder à vouloir les remplire de manière hachurée verticalement, puis sous différentes versions de dégradé, puis à l'aide d'images récupérées par ailleurs, puis... l'imagination est sans limite

    Si tu décide à chaque fois de faire dériver une classe (particulière) de Rectangle pour chaque type de remplissage, tu va te retrouver au final avec cinq, dix ou vingt classes dérivées de rectangle, auxquelles tu devra rajouter un nombre équivalent pour les cercles, les triangles, les étoiles ou que sais-je... Bref, tu assistera à une véritable explosion du nombre de tes classes...

    Alors que si, comme je te le conseille, tu te dis que, finalement, la manière dont une forme est remplie est indépendante de la forme elle-même, et donc que tu délègue la responsabilité du remplissage à une classe à part, tu pourra, en ne créant qu'un nombre limité de classes pour les différents types de remplisage et en fournissant une instance d'une de celle-ci à tes différentes formes, obtenir toutes les combinaisons envisageables.

    Nous aurions donc quelque chose de proche de
    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
    /* classe de base qui fournit l'interface commune */
    class AbstractFiller
    {
        /* ... */
    };
    /* classe pour un remplissage "uni" */
    class PlainFiller : public AbstractFiller
    {
        /* ...*/
    };
    /* classe pour un remplissage hachuré horizontal */
    class HStrippedFiller : public AbstactFiller
    {
    };
    /* pour un hachuré vertical */
    class VStrippedFiller : public AbstractFiller
    {
    };
    /* pour les différents types de dégradés, les image, les choses et 
     * les bidules
     * ...
     */
    il "suffira" alors de passer une référence sur AbstractFiller à la fonction draw de tes différentes formes et d'utiliser l'interface commune pour travailler:
    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
    class Rectangle : public shape
    {
        public:
            virtual void draw(AbstractFiller & filler) const
            {
                /* uses filler to determine how the rectangle is filled */
            }
    };
    class Circle: public shape
    {
        public:
            virtual void draw(AbstractFiller & filler) const
            {
                /* uses filler to determine how the circle is filled */
            }
    };
    class Triangle: public shape
    {
        public:
            virtual void draw(AbstractFiller & filler) const
            {
                /* uses filler to determine how the triangle is filled */
            }
    };
    class Star: public shape
    {
        public:
            virtual void draw(AbstractFiller & filler) const
            {
                /* uses filler to determine how the star is filled */
            }
    };
    J'en profite pour rappeler une princip trop souvent oublié en conception : le principe de la responsabilité unique (Single Responsability Principle) qui considère que, si une classe ou une fonction a plus d'une responsabilité doit faire plus d'une seule chose, c'est sans doute qu'elle doit en faire trop (le tout étant de trouver une granularité acceptable pour les responsabilités )
    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

  13. #13
    Membre habitué Avatar de bringer
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Points : 137
    Points
    137
    Par défaut
    merci beaucoup de tes conseils koala01

    Pour la définition de la classe rectangle, elle est dans les sources dans le fichier Graph.h et cpp. C'est le modèle fournir par le livre.

    Effectivement ce que tu me dis semble parfaitement logique. Le soucis maintenant et de définir comment la classe filler peut connaitre et adapter le remplissage à la forme.
    Il est vrai que dans un premier temps je me suis dit que c'est la forme elle même qui sait le mieux comment elle doit être remplie. De plus, l'exo du livre demande de dériver Striped_rectangle de rectangle.
    Enfin, les classes Rectangle, Circle etc.. fourni par le livre sont considérées comme étant des classes bibliothèque et de ce fait, je ni touche pas. Je ne peut que m'appuyer dessus.

    Pour mon dernier post, j'ai trouvé la réponse. Il fallait que j'appel une fonction draw() de la classe Shape qui gère les propriétés couleur et type de ligne, au lieu d'appeler la fonction draw_line() qui se contente de tracer les lignes.

    Je pense que je comprend un peu mieux les mécanismes avec toute ces triturations et c'est déjà bien pour moi.
    Je prend bonne note de tous ces conseils.

    merci.
    bringer

  14. #14
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Tu es, en réalité, confronté à un problème qui nécessite une double solution:

    Tu dois en fait considérer que tes formes proposent deux comportements:
    • le comportement qui consiste à se tracer
    • le comportement qui consiste à se remplir
    Ces deux comportements peuvent d'ailleurs être regroupés en un troisième comportement : celui qui consiste à se paindre...
    On peut estimer que les fonctions draw de Rectangle, Circle et les autres fournissent le comportement adéquat, quel que soit le style de remplissage attendus, mais qu'il nous faut par contre une hiérarchie de classe capable de se remplire.

    La classe de base de cette hiérarchie hériterait de... shape et proposerait une fonction virtuelle (pure) supplémentaire : paint(Painter &) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class FillableShape : public Shape
    {
        public:
            virtual void paint(painter & ) const = 0;
    }
    A partir de là, nous pourrions créer une série de classes héritant de FillableShape pour nos différentes formes pouvant être remplies. Elle seraient toutes composées, en interne, de la forme "simple" correspondante de manière à pouvoir accéder aux comportements qui nous intéressent (dont, entre autre, celui de tracer les contours )
    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
    class FillableRectangle : public Shape
    {
        public:
            virtual void paint(Painter & painter) const
           {
               /* on commence par tracer le rectangle */
               m_rectangle.draw();
               /* puis on délègue au "painter" le fait de le
                * remplir ... cf plus bas
                */
               painter.paint(m_rectangle); 
           }
        private:
           Rectangle m_rectangle;
    };
    /* nous faisons pareil pour les différentes formes */
    class FillableCircle : public Shape
    {
        public:
            virtual void paint(Painter & painter) const
           {
               /* on commence par tracer le rectangle */
               m_circle.draw();
               /* puis on délègue au "painter" le fait de le remplir ...
                * cf plus bas
                */
               painter.paint(m_circle); 
           }
        private:
           Circle m_circle;
    };
    /* ... */
    D'un autre coté, nous utiliserions le Desing Pattern Visiteur pour gérer la manière dont les différentes formes sont remplies.

    Le principe est d'appliquer un "double dispatch" sur nos objets en déléguant les responsabilités:

    A partir du moment où les formes sont tracée, c'est un autre objet (ici de type "Painter") qui va se charger, sur base des informations dont il dispose (telles que la couleur de remplissage ou l'épaisseur des traits) et de quelques informations fournies par la forme à remplir (telles que la position du coin supérieur gauche, la hauteur de la forme, sa largeur ou son diamètre si c'est un cercle) de remplir effectivement la forme.

    L'avantage est que tu va éviter d'avoir une explosion du nombre de tes classes qui pourrait atteindre le nombre de "style de remplissage" multiplié par le nombre de formes, l'inconvénient étant que, si tu décide un jour de rajouter une classe de forme au niveau de la bibliothèque ( Pentagon ) tu sera tenu de... modifier toutes les classes se chargeant du remplissage pour qu'elle accepte cette nouvelle forme.

    Pour profiter au mieux du polymorphisme, la classe visiteur ("Painter" en fait) ressemblerait donc à quelque chose comme
    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
    class Painter
    {
        public:
            /* Une fonction par classe de forme envisagée
             *
             * uniquement des fonctions virtuelles pures, car on
             * ne dispose, à ce stade, pas des informations qui
             * nous permettraient de donner un comportement
             * par défaut ...
             *
             * à moins qu'on considère le fait de laisser les formes
             * vides comme étant un comportement par défaut
             * plausible ???
             */
     
            virtual void paint(Rectangle const &) = 0;
            virtual void paint(Circle const &  ) = 0;
            virtual void paint(Star const & ) = 0;
            virtual void paint(Triangle const & ) = 0;
            /* toutes les autres ... */
    };
    /* la spécialisation pour remplire les forme "unies" */
    class PlainPainter : public Painter
    {
        public:
            /* tout ce qu'il nous faut, c'est de pouvoir définir la
             * couleur de remplissage
             */
          void setColor(Color const & newColor){m_color = newColor;}
           /* les fonctions de remplissage avec une couleur unie */
            virtual void paint(Rectangle const & rect)
            {
                /* définition des "points intéressants" tels que le
                 * coin supérieur gauche, le coins inférieur droit, 
                 *etc et remplissage avec la couleur donnée
                 */
            }
            virtual void paint(Circle const & circle )
            {
                /* définition des "valeurs intéressantes" telless 
                 * que le centre et le rayon, etc et remplissage
                 * avec la couleur donnée
                 */
            }
            virtual void paint(Star const & star )
            {
                /* toujours pareil :-D */
            }
            virtual void paint(Triangle const & ) 
            {
                /* toujours pareil :-D */
            }
            /* toutes les autres ... */
    };
    /* une autre pour le remplissage hachuré vertical*/
    class VStrippedPainter  : public Painter
    {
        public:
            /* même chose que pour PlainPainter, mais adapté
             * au fait que l'on veut des hachures 
             */
    };
    /* faire pareil pour les hahure horizontales
     * (HStrippedPainter ?? ), les différents dégradés possible,
     * les image etc...
     */
    L'utilisation sera alors proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int main()
    {
        FillableRectangle myRect();
        /* définition des valeurs qui vont bien pour le rectangle */
        /* je veux remplir mon rectangle avec des hachures verticales
         */
        VStrippedPainter painter; 
       /* définition de la couleur, de la largeur des traits, et des
        * autres caractéristiques des hachures
        */
       myRect.draw(painter);
        /* ... */
    }
    C'est, bien sur, l'utilisation "de base", mais il existe de nombreuses autres possibilités
    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

  15. #15
    Membre habitué Avatar de bringer
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Points : 137
    Points
    137
    Par défaut
    bonjour koala01 et désolé de ne pas pouvoir te répondre plus tôt. (2 gnomes en bas age, ça occupe quand même...)

    bon, j'ai bien lu, relu, rerelu, enfin bon, j'ai essayé de comprendre le dernier post, mais mon niveau de programmation semble encore insuffisant. Je comprend bien l'intérêt des design patern, mais pour le moment, je ne pense pas être en mesure de pouvoir tout intégrer dans ce domaine.
    J'y reviendrais sans doute plus tard. Pour l'instant je mets tout cela dans un petit coin de mémoire et je continu le livre de B. Stroustrup sur la même lancée.

    merci beaucoup de toute votre aide.

    bringer.

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

Discussions similaires

  1. [Probleme de Compréhension] Nom des dossier
    Par brak__ dans le forum Windows Vista
    Réponses: 9
    Dernier message: 27/02/2007, 09h37
  2. [Mapping] probleme de compréhension
    Par chaby dans le forum Hibernate
    Réponses: 5
    Dernier message: 10/11/2006, 11h55
  3. probleme de compréhension de proxy
    Par Mut dans le forum Applications
    Réponses: 3
    Dernier message: 11/01/2006, 12h24
  4. Réseau....probleme de compréhension
    Par Mut dans le forum Administration
    Réponses: 7
    Dernier message: 10/06/2005, 16h42
  5. [C#] Probleme sur les clés primaires composites
    Par stardeus dans le forum Windows Forms
    Réponses: 7
    Dernier message: 12/02/2005, 23h28

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