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 :

aide pour la conception avec heritage multiple


Sujet :

C++

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2011
    Messages
    96
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 96
    Par défaut aide pour la conception avec heritage multiple
    Bonjour
    Le probleme qui m'est pose est le suivant:
    + dans un premier temps on veut modeliser un parallelogramme puis ces classes deriver losange et rectangle.
    + dans un second temps on veut ajouter le carre tout en factorisant le code au maximum j'adjoins les 2 codes que j'ai produit.

    premier cas: sans les carre
    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
    104
    105
    106
    107
    108
    109
     
    class Parallelogramme {
     
    	protected:
    		double largeur;
    		double longueur;
    		double angle;
     
    	public:
     
    		// constructeur 		
    		Parallelogramme::Parallelogramme(double l = 0, double L = 0, double a = 0) {
     
    			largeur = l;
    			longueur = L;
    			angle = a;
     
    		}
     
    		AllongerX(double coeff) { 
     
    			largeur = largeur * coeff;
     
    		}
     
    		AllongerY(double coeff) { // L
     
    			longueur = longueur * coeff;
     
    		}
     
    		ChangerAngle(double coeff) {
     
    			angle = angle * coeff;
     
    		}
     
    		void setLargeur(double l) {
     
    			largeur = l;
     
    		}
     
    		void setLongueur(double L) {
     
    			longueur = L;
     
    		}
     
    		void setAngle(double a) {
     
    			angle = a;
     
    		}
     
    		double getLargeur() {
     
    			return largeur;
     
    		}
     
    		double getLongueur() {
     
    			return longueur;
     
    		}
     
    		double getAngle() {
     
    			return angle;
     
    		}
    }
     
    class rectangle : public A {
     
    	protected:
    		double largeur
    		double longueur;
     
    	public:
    		// constructeur
    		rectangle::rectangle(double l, double L) : Parallelogramme(l, L), angle(90) {
     
     
     
    		}
    		// constructeur par recopie
    		rectangle(rectangle  &r) : Parallelogramme(r), largeur(r.largeur), longueur(r.longueur) {}
    }
     
     
     
    class losange : public A {
     
    	protected:
    		double cote;
    		double angle
     
    	public:
    		// constructeur
    		losange::losange(double c, double a) : Parallelogramme(c, c, a) {
     
     
     
    		} 
    		// constructeur par recopie
    		losange(losange &lo) : Parallelogramme(lo), c(lo.c) {}
    }
    second cas: avec les carre

    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
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
     
    class Parallelogramme {
     
    	protected:
    		double largeur;
    		double longueur;
    		double angle;
     
    	public:
     
    		// constructeur par defaut pour la derivation virtuelle
    		Parallelogramme() {}
     
    		Parallelogramme::Parallelogramme(double l = 0, double L = 0, double a = 0) {
     
    			largeur = l;
    			longueur = L;
    			angle = a;
     
    		}
    		AllongerX(double coeff) { 
     
    			largeur = largeur * coeff;
     
    		}
     
    		AllongerY(double coeff) { 
     
    			largeur = largeur * coeff;
     
    		}
     
    		ChangerAngle(double coeff) {
     
    			angle = angle * coeff;
     
    		}
    		/*
    		* manque getter et setter
    		*/
    		void setLargeur(double l) {
     
    			largeur = l;
     
    		}
     
    		void setLongeur(double L) {
     
    			longueur = L;
     
    		}
     
    		void setAngle(double a) {
     
    			angle = a;
     
    		}
     
    		double getLargeur() {
     
    			return largeur;
     
    		}
     
    		double getLongueur() {
     
    			return longueur;
     
    		}
     
    		double getAngle() {
     
    			return angle;
     
    		}
    }
     
    class rectangle : virtual public A {
     
    	protected:
    		double largeur;
    		double longueur
     
    	public:
    		// constructeur
    		rectangle::rectangle(double l, double L){
     
     
     
    		}
    		// constructeur par recopie
    		rectangle(rectangle  &r) : Parallelogramme(r), largeur(r.largeur), longueur(r.longueur) {}
    }
     
     
     
    class losange : virtual public A {
     
    	protected:
    		double cote;
    		double angle;
     
    	public:
    		// constructeur
    		losange::losange(double c, double a) {
     
     
     
    		} 
    		// constructeur par recopie
    		losange(losange &lo) : Parallelogramme(lo), cote(lo.cote), angle(lo.angle) {}
    }
     
     
    class carre : public rectangle, public losange {
     
    	protected:
    		double cote;
     
    	public:
    		carre::carre(double c) : Parallelogramme(c, c, a) : rectangle() : losange() { // rectangle(l, l) : losange(l, 90)
     
     
     
    		}
     
    }
    n'etant en rien certain de l'aspect conception avec heritage multiple et classe virtuelle, j'attend vos critiques
    par avance merci

  2. #2
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    Dans le cas d'un héritage multiple en losange (comme dans ton exemple), la classe la plus dérivée qui a la responsabilité d'appeler les constructeur, non seulement des ses classes mères directe, mais en plus de la classe mère commune.
    C'est à dire que tu peux déjà laisser les appels au constructeur de Parallélogramme dans Losange et Rectangle, ils ne seront appelés que si la classe instanciée est réellement un Losange ou et un Rectangle ( mais pas quand c'est un carré )
    Pour ce qui du constructeur de Carre, il faut mettre des virgule entre les appels aux constructeur des classes parentes et non des "deux-points".
    Enfin l’héritage ne me convainc pas du tout. Dans le cas de forme géométrique, l’héritage ne peut avoir de sens que si les objet sont immuables (je te renvoie à la FAQ, pour comprendre les dangers de ta conception actuelle) et que les méthode ne servent connaître des propriété de l'objet ( les diagonales se coupent-elles en leur milieu ? les cotés sont ils tous égaux ?, ...)
    Dernière modification par Invité ; 10/12/2011 à 19h29.

  3. #3
    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,

    Le fait est que, bien que le carré soit un rectangle et un losange au sens mathématique du terme, il ne l'est pas au sens du respect du LSP

    LSP (Liskov Substitution Principle, ou, si tu préfères en français, le Principe de Substitution de Liskov) nous dit en effet
    Citation Envoyé par Barbara Liskov(traduction libre ;))
    Soit deux objets A et B, B héritant de A, toute propriété valide de A doit etre valide pour B.
    Globalement, cela implique plusieurs restrictions dont (entre autre) le fait que toute fonction publique valide du type de base se doit etre valide pour le type dérivé (modulo l'éventuelle adaptation du comportement)


    Or, pour le rectangle, tu vas fournir les notions de longueur et de largeur, et pour le losange, tu vas fournir les notion de petite et de grande diagonale.

    Ces notions n'ont strictement aucun sens dans un carré, vu que longueur == largeur (nous parlerons d'ailleurs de coté) et que diagonale1 == diagonale2 !!!

    les fonctions destinées à modifier ou à obtenir une diagonale particulière (qui serait héritée de losange) d'une part et la longueur ou la largeur (qui seraient héritée de rectangle) d'autre part sont donc invalides pour le carré: il n'y aurait absolument aucun sens à invoquer une fonction tel que "setDiagonale1", "setDiagonale2", "setLongueur" ou "setLargeur" pour un carré, simplement parce que ce sont des notions qui n'existent pas.

    De plus, si ces fonctions font ce qu'elles sont sensées faire (et rien de plus ! ) les post conditions permettant de nous assurer que nous avons toujours bel et bien un carré (diagonale1 == diagonale2 et coté1==coté2 ) seront violées.

    Bref, tout cela pour dire que, décidément, tu ne peux en aucun cas considérer que carré hérite ni de rectangle ni de losange.

    Il reste donc deux solutions :
    • Soit tu considère que carré hérite de parallélogramme et que ce n'est ni un losange ni un rectangle (nous pourrions dire que carré se trouve au meme niveau que rectangle et que losange dans la hiérarchie des classes )
    • Soit tu considère que le carré est "simplement" une sorte d'état particulier, un état remarquable (respectivement parce qu'il a des diagonales ou des cotés égaux ) que l'on peut retrouver dans un losange ou dans un rectangle

    [NOTA]J'aurais, à vrai dire, pu baser toute une argumentation sur des principes issus de la programmation par contrat (préconditions, postconditions et invariants), le résultat aurait été tout à fait identique, mais tu aurais sans doute eu beaucoup plus de mal à comprendre si tu n'as pas encore abordé ce genre de sujet .
    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

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2011
    Messages
    96
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 96
    Par défaut
    Bonjour
    Tout d'abord merci pour votre attention.

    Citation Envoyé par Joe Dralliam Voir le message
    Enfin l’héritage ne me convainc pas du tout.
    d’après la FAQ je suis d'accord avec vous cependant, d’après l’énonce de mon exercice, je ne vois pas comment faire autrement.

    il m'est demande "de construire la hiérarchie de classe représentant les parallélogramme généraux , les rectangles et les losanges (classes avec attributs et constructeur)"
    Puis de rajouter des méthodes, a la classe racine (et de les redéfinir si besoin dans les classes filles) pour faire des transformations (allongerX allongerY, changerAngle) qui ne transforme pas la nature du quadrilatère.
    Ensuite de rajouter une méthode pivoter
    Enfin d’implémenter une classe carre (losange rectangle) avec les même méthodes qui "devra justifier les modification apportes dans les autres classe pour son implémentation".Tout en prenant en compte le fait "qu'il sera tenu compte de la factorisation du code car toute duplication de code sera sanctionnée"
    si joint un visuel d'un parallélogramme et de sa transformation
    Images attachées Images attachées   

  5. #5
    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
    Hé bien, il ne te reste plus qu'une seule chose à faire : faire lire ma prose à ton prof et lui dire que cette dernière partie de l'exercice n'est pas correcte d'un point de vue conceptuel

    Désolé, mais ton prof est sans doute plus un mathématicien qu'un concepteur

    Tu peux aussi ( car il ne sera pas obligé de me croire sur parole ) l'envoyer sur la page associée au LSP de wikipedia, et, principalement à la section Typical violation (qui parle justement du problème losange <--> carré <--> rectangle )

    [EDIT]Je me doute que l'idée que ton prof a derrière la tête est de vous amener à envisager ce que l'on appelle "l'héritage en losange (ou en diamant) ou encore "le losange de la mort" et donc à introduire la notion d'héritage virtuel...

    Seulement, l'exemple n'est absolument pas adapté (car il viole LSP qui est un principe de conception fondamental)!

    De plus, un héritage en diamant indique souvent qu'il y a un problème de conception à la base dans le sens où l'on a sans doute choisi une granularité beaucoup trop fine au niveau de la classe ancêtre.

    Ce n'est en effet pas un hasard si des langages tels que Java ou C#, qui font systématiquement (et silencieusement) hériter toute classe d'un "super objet" (la classe Object, ou similaire) interdisent l'héritage multiple

    C'est uniquement pour éviter de se retrouver dans ce genre de situation
    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 confirmé
    Profil pro
    Inscrit en
    Février 2011
    Messages
    96
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 96
    Par défaut
    Citation Envoyé par koala01 Voir le message
    faire lire ma prose à ton prof et lui dire que cette dernière partie de l'exercice n'est pas correcte d'un point de vue conceptuel
    votre reponse me deroute car il s'agit d'un examen donc d'une part on n'a guere le temps pour s'attarder a des "details" de conception car la conception general nous est donne il faut la coder. Deplus comme c'est dans un examen l'heure n'est plus a l'apprentissage n'y a
    introduire la notion d'héritage virtuel
    Désolé, mais ton prof est sans doute plus un mathématicien qu'un concepteur
    Son dada c'est la compilation, ca a d'ailleur etait sa maniere de faire le cours, du point de vue du compilateur

    je joins le pdf de l'examen
    Images attachées Images attachées

  7. #7
    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
    Citation Envoyé par Torx26 Voir le message
    votre reponse me deroute car il s'agit d'un examen donc d'une part on n'a guere le temps pour s'attarder a des "details" de conception car la conception general nous est donne il faut la coder. Deplus comme c'est dans un examen l'heure n'est plus a l'apprentissage n'y a
    S'il ne s'était agit de C++, ton prof ne t'aurais jamais demandé de faire hériter carré de losange et de rectangle, entre autre parce que l'héritage multiple est interdit dans ces autres langages.

    C++ donne beaucoup de libertés au codeur (certains trouvent même qu'il en donne trop ) ce qui implique que l'on doit être particulièrement attentif à avoir une conception sans faille à la base, autrement, on fonce dans le mur.

    Cela implique que la conception se doit de respecter scrupuleusement les principes qui la régissent!!!

    A partir du moment où une conception est foireuse (et c'est le cas ici), la meilleure solution en tant que "pisseur de code" est encore de la refuser et de demander de la revoir.

    A la lecture de l'énoncé, et pour respecter LSP, nous ne pourrions meme pas prétendre que carré est un parallélogramme parce que l'interface que parallélogramme devrait exposer n'est purement pas applicable à un carré: seules les méthodes pivoter et changerAngle seraient susceptibles d'être utilisée pour un carré

    En effet, les invariants propres à un carré (L == l, D1 == D2 ), le pré et post conditions qui en découlent sont purement et simplement incompatibles avec les invariants génériques d'un parallélogramme !

    Pour moi, la seule réponse envisageable pour le 4.D est : désolé, je ne peux pas le faire, carré n'est ni un rectangle ni un losange à cause du principe connus sous le nom de LSP"
    Son dada c'est la compilation, ca a d'ailleur etait sa maniere de faire le cours, du point de vue du compilateur

    je joins le pdf de l'examen
    Il a peut etre parfaitement compris le principe de la compilation, mais cela n'empêche que seule la politesse m'empêche de dire ce que je pense de lui au niveau de la conception
    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

  8. #8
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    Citation Envoyé par Torx26 Voir le message
    votre reponse me deroute car il s'agit d'un examen donc d'une part on n'a guere le temps pour s'attarder a des "details" de conception car la conception general nous est donne il faut la coder. Deplus comme c'est dans un examen l'heure n'est plus a l'apprentissage n'y a


    Son dada c'est la compilation, ca a d'ailleur etait sa maniere de faire le cours, du point de vue du compilateur

    je joins le pdf de l'examen
    Tu réalises, bien évidemment, que tu postes un sujet d'examen sur un forum public, n'est-ce pas ?
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  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
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    Tu réalises, bien évidemment, que tu postes un sujet d'examen sur un forum public, n'est-ce pas ?
    examen du 18 décembre 2008. Ca va. C'est plutôt consciencieux de sa part de s'entrainer avec les exam des années passées.


    @Torx26 : la seule façon de t'en sortir est de passer toutes les fonctions de modification en virtuelle afin de permettre aux classes dérivées d'assurer leur cohérence.

  10. #10
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 296
    Par défaut
    Pour compléter la prose de Koala, le seul cas où il est acceptable de dire qu'un carré est un rectangle & cie, c'est si on a un vrai carré mathématique, soit un truc qui ne peut pas être altéré.
    À partir du moment où tu rajoutes du comportement, c'est fini, avec ces objets-ci.

    Tu peux aussi renvoyer ton prof vers cette ancienne discussion: http://www.developpez.net/forums/d60...rre-rectangle/

    Dernier point : avant de faire de l'héritage multiple, et surtout en C++, il est impératif de comprendre le LSP. Sans ça tu n'aboutiras jamais à rien de correct.
    Avec le LSP maitrisé et exploité dans la conception, les héritages multiples passent généralement tous seuls, et sans se mettre en embuscade pour nous exploser à la figure à la première occasion.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

Discussions similaires

  1. Réponses: 16
    Dernier message: 01/02/2007, 16h04
  2. Aide pour un warning avec RegSetValueEx
    Par Pierre.g dans le forum Windows
    Réponses: 4
    Dernier message: 24/08/2006, 14h46
  3. [VB] Aide pour la conception d'un jeu
    Par superbruno dans le forum VB 6 et antérieur
    Réponses: 12
    Dernier message: 17/01/2006, 18h01
  4. [PHP-JS] besoin d'aide pour menu déroulant avec lien
    Par Damarus dans le forum Langage
    Réponses: 3
    Dernier message: 06/10/2005, 18h43
  5. Conception avec héritage
    Par Mr N. dans le forum Diagrammes de Classes
    Réponses: 31
    Dernier message: 04/07/2005, 18h59

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