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

Langage C++ Discussion :

Méthode de comparaison et héritage


Sujet :

Langage C++

  1. #1
    Nouveau Candidat au Club
    Inscrit en
    Mai 2013
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Mai 2013
    Messages : 4
    Points : 1
    Points
    1
    Par défaut Méthode de comparaison et héritage
    Bonjour,

    J'ai des classes héritant d'une classe possédant une méthode compare. J'aimerais surcharger ces méthodes dans les classes filles comme dans l'exemple suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class A
    {
    public:
    	virtual void compare(A& a) { std::cout << "A"; }
    };
     
    class B : public A
    {
    public:
    	void compare(B& b) { std::cout << "B"; }
    };
    Le virtual ne sert à rien ici et le code suivant retourne "A".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    B b1, b2;
    A * a1, * a2;
    a1 = &b1;
    a2 = &b2;
    a1->compare(*a2);
    Le problème c'est que lors que je dois appeler compare je n'ai que des pointeurs ou des références sur A. Est-ce que j'ai une solution pour gérer ça simplement?

    Merci

  2. #2
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    A vue de nez ce n'est pas une redéfinition car les signatures diffèrent. Donc il est logique que ce soit bien A::compare qui soit appelé...
    Pour avoir le comportement polymorphe demandé, je suggère plutôt:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    class B:public A{
      void compare(A& a){std::cout << "B"};
    }

  3. #3
    Nouveau Candidat au Club
    Inscrit en
    Mai 2013
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Mai 2013
    Messages : 4
    Points : 1
    Points
    1
    Par défaut
    Merci pour la réponse. Le problème c'est que j'ai absolument besoin d'un B pour que la comparaison soit possible. Je pourrais faire un static_cast mais ça me parait pas terrible et ça fonctionne pas si on fait ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    B b1;
    A a2;
    A * a1;
    a1 = &b1;
    a1->compare(a2);

  4. #4
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Salut

    C'est amusant comme parfois, les réponses anticipes les questions : Herb Sutter à justement abordé en détail ta problématique dans le GOTW 5 de la semaine dernière : http://herbsutter.com/2013/05/22/got...ual-functions/
    Regarde en particulier la partie Interlude et les définitions de override (redéfinition), overload (surcharge) et hide (masquage).

    Ce que tu fais n'est ni une surcharge (les deux fonctions compare ne sont pas dans la même portée), ni une redéfinition (les deux fonctions n'ont pas les mêmes paramètres). C'est donc un masquage

    Ensuite, c'est un problème de type dynamique et statique. Ta variable a1 est de type statique A et n'as pas de redéfinition (pas de fonction virtuelle correspondant pour le type dynamique de a1, qui est le type B) de la fonction compare, donc c'est bien A::compare qui est appelé

    Si tu veux appeler B::compare, soit tu utilises le type statique B :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static_cast<B*>(a1)->compare(*static_cast<B*>(a2));
    soit tu changes la signature de B::compare pour bénéficier de la redéfinition :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class B : public A
    {
    public:
    	void compare(A const& b) { std::cout << "B"; }
    };
    HS : utilise const& si tu ne modifies pas tes paramètres de fonctions

    Bon courage

  5. #5
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Citation Envoyé par Curvabirra Voir le message
    Le problème c'est que j'ai absolument besoin d'un B pour que la comparaison soit possible.
    Là tu es à contre-emploi en ce qui concerne la polymorphie. La redéfinition n'a de sens que si tu peux employer indifféremment tout type dérivé de A. Sinon tu es probablement face à un problème de conception.
    Tu devrais soit pouvoir manipuler aveuglément une instance par une référence ou un pointeur de type A, que le type effectif soit A ou B, soit utiliser explicitement des instances de type B.
    En effet, la dérivation signifie qu'un B est utilisable "comme un A", donc la comparaison d'un A à un B doit être définie (définie avec quel résultat, ça ça dépend de ce qu'est ta comparaison (relation d'ordre? test d'égalité?)).
    Donc la question devient "à quoi me sert-il de pouvoir manipuler B comme un A?"

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

    En outre, il faut se dire que les classes intervenant dans une hiérarchie d'héritage ont typiquement une sémantique d'entité.

    L'un des points remarquable de ce genre de classe est que tu peux sans doute envisager de comparer certaines propriétés communes, mais qu'il est impossible de comparer de manière "globale" deux objets de type différents.

    Comment voudrais tu arriver à comparer un avion avec une voiture (ou un sous-marin) si ces différents types héritaient tous de la classe véhicule

    Si les propriétés sont présentes au niveau de la classe mère (mettons : la propriété autonomie, bien qu'elle n'ait aucun sens pour les véhicules à vent ou à pédale ) tu peux comparer l'autonomie d'une voiture avec celle d'un avion ou d'un sous-marin, mais il ne faut pas être grand clerc pour se rendre compte que les valeurs seront sans doute sans commune mesure

    D'un autre coté, si tu veux comparer deux voitures entre elles, il faudra, de toutes manière, décider de l'ordre utilisé pour comparer les différentes propriétés, et cet ordre est susceptible de changer à chaque fois

    Enfin, la seule égalité possible entre deux véhicules est celle qui permettra d'identifier chaque véhicule de manière "unique et non ambiguë" car tu ne voudrais pas de ta voiture soit confondue avec celle de ton voisin
    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

  7. #7
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Mais peut-être notre posteur veut-il comparer des voitures et des autocars en terme de capacité de transport de personnes?

  8. #8
    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
    Citation Envoyé par therwald Voir le message
    Mais peut-être notre posteur veut-il comparer des voitures et des autocars en terme de capacité de transport de personnes?
    A ce moment là, la responsabilité de la comparaison n'échoit pas aux véhicules, mais à une fonction ou à un foncteur dédié(e)
    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

  9. #9
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Donc voilà bien le schmilblick: en terme de conception propre, ça devrait plutôt être une surcharge (et non une redéfinition) dans un espace de nommage ou une unique classe (sans notion d'héritage en tous cas...).
    Dans ce cas, la règle offrant de comparer seulement A à A et B à B revient à n'écrire que:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <resultat_t> compare(const A&, const A&)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <resultat_t> compare(const B&, const B&)

  10. #10
    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
    Citation Envoyé par therwald Voir le message
    Donc voilà bien le schmilblick: en terme de conception propre, ça devrait plutôt être une surcharge (et non une redéfinition) dans un espace de nommage ou une unique classe (sans notion d'héritage en tous cas...).
    Dans ce cas, la règle offrant de comparer seulement A à A et B à B revient à n'écrire que:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <resultat_t> compare(const A&, const A&)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <resultat_t> compare(const B&, const B&)
    En allant meme sans doute beaucoup plus loin, car tu peux comparer n'importe quelle propriété de tes classes.

    La comparaison de deux objets sur une propriété P1 n'a pas forcément de relation étroite avec la comparaison de ces deux mêmes objet sur une propriété P2.

    Et je ne te parle pas, bien évidemment de toutes les combinaisons possibles que l'on peut envisager sur base des différentes propriété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

  11. #11
    Nouveau Candidat au Club
    Inscrit en
    Mai 2013
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Mai 2013
    Messages : 4
    Points : 1
    Points
    1
    Par défaut
    Il s'agit d'un code utilisé dans le cadre d'un logiciel de dessin en bâtiment. La classe A représente un élément de base (position, dimension, qualité de béton, ...). Cette classe possède plusieurs classe filles (Dalle, Mur, ...) représentées par B ici.

    La méthode compare permet de déterminer si des éléments peuvent être fusionnés. Si on compare une dalle et un mur elle doit toujours retourné false. Par contre, si l'on compare deux dalles, plusieurs règles métier propres aux dalles doivent être prises en compte.

    Mon problème est que, la plupart du temps, des pointeurs ou références de la classe A sont utilisés. Je n'arrive pas vraiment à trouver de solution acceptable à ce problème. Est-ce qu'il y a vraiment un soucis de conception?

  12. #12
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Est-ce qu'il y a vraiment un soucis de conception?
    Oui: tu veux traiter des éléments de manière homogène avec des comportements différenciés en fonction des sous-types, donc tu dois définir une interface ('compare', dont le nom est peut-être un peu ambigü, ça ça relève de ta politique de nommage, personnellement je choisirais un nom plus parlant) homogène.
    Le problème devant lequel tu as est celui dit du 'double dispatch' (le comportement ne dépend pas du type d'un des deux objets impliqués, mais du type des deux.
    Il me semble que le pattern 'Visitor' est la solution de conception qui convient.

  13. #13
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Je trouve étonnant de ne pas avoir des "plans" {sol, mur, plafond} reproduites par étages.

    Avec ce fonctionnement, je ne mets pas de mur là ou je pourrais avoir une dalle, et vice versa

    Par contre, il y a un frère: dessinable, qui sert pour l'interface graphique, et peut représenter une dalle, un mur…
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  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
    Citation Envoyé par Curvabirra Voir le message
    Il s'agit d'un code utilisé dans le cadre d'un logiciel de dessin en bâtiment. La classe A représente un élément de base (position, dimension, qualité de béton, ...). Cette classe possède plusieurs classe filles (Dalle, Mur, ...) représentées par B ici.

    La méthode compare permet de déterminer si des éléments peuvent être fusionnés. Si on compare une dalle et un mur elle doit toujours retourné false. Par contre, si l'on compare deux dalles, plusieurs règles métier propres aux dalles doivent être prises en compte.

    Mon problème est que, la plupart du temps, des pointeurs ou références de la classe A sont utilisés. Je n'arrive pas vraiment à trouver de solution acceptable à ce problème. Est-ce qu'il y a vraiment un soucis de conception?
    Oui, très certainement

    Je vais prendre le temps de réfléchir un tout petit peu au problème, je reviendrai avec une solution "correcte" sous peu

    [EDIT]En fait, je crois l'avoir, mais, avant tout, il me faudrait quelques précisions...

    Quand tu parle de "position" est-ce au sens "coordonnées" (abscisse / ordonnée) du terme, au sens "orientation" (nord, haut, ...) ou au sens "mur, plafont, toit"

    Je parlerai du mur plus tard, mais je ne crois pas qu'il ait sa place dans cette hiérarchie (par contre "brique" ou "linteau" "seuil de porte" ou "appui de fenetre" pourraient l'avoir )
    [/EDIT]
    Citation Envoyé par therwald Voir le message
    Oui: tu veux traiter des éléments de manière homogène avec des comportements différenciés en fonction des sous-types, donc tu dois définir une interface ('compare', dont le nom est peut-être un peu ambigü, ça ça relève de ta politique de nommage, personnellement je choisirais un nom plus parlant) homogène.
    Le problème devant lequel tu as est celui dit du 'double dispatch' (le comportement ne dépend pas du type d'un des deux objets impliqués, mais du type des deux.
    Il me semble que le pattern 'Visitor' est la solution de conception qui convient.
    Je ne suis même pas sur que le pattern visiteur soit particulièrement efficace sur ce coup là.

    il faut bien te dire que, pour l'instant, l'idée est de comparer un T* avec un U* (tel que T et U peuvent représenter un type identique... ou non )

    Le patron visiteur est très bien lorsque tu veux travailler avec le type réel (dynamique) d'un seul objet que tu ne connais que sous la forme de son type de base
    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 expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Tu pourrias peut-être tenter quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class Mur;
    class Dalle;
    class Fusable{
    public:
     
    virtual bool visitFusable(const Mur & mur){return false;};
    virtual bool visitFusable(const Dalle & dalle){return false};
     
    virtual bool fuseable(const Fusable & fusable)=0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    #include "Fusable.h"
    class Mur: public Fusable{
       public:
    bool fusable(const Fusable & fusable){
       return fusable.visitFusable(*this);
    }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    #include "Fusable.h"
    class Dalle: public Fusable{
       public:
    bool fuseable(const Fusable & fusable){
       return fusable.visitFusable(*this);
    }
    bool visitFusable(const Dalle & dalle){
      return true;
    }
    }

  16. #16
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    @koala: c'est mon tour de me faire griller

  17. #17
    Nouveau Candidat au Club
    Inscrit en
    Mai 2013
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Mai 2013
    Messages : 4
    Points : 1
    Points
    1
    Par défaut
    Effectivement le visitor pattern résout mon problème. Merci.

    Concernant la conception:

    Citation Envoyé par koala01
    Quand tu parle de "position" est-ce au sens "coordonnées" (abscisse / ordonnée) du terme, au sens "orientation" (nord, haut, ...) ou au sens "mur, plafont, toit"
    Ça détermine l'emplacement de l'élément dans la construction (1er étage pour un bâtiment, tablier pour un pont, ...). Ces données sont utilisées pour des calculs de statique par exemple.

Discussions similaires

  1. Méthodes de comparaison shazam
    Par bachintosh dans le forum Algorithmes et structures de données
    Réponses: 6
    Dernier message: 19/01/2012, 23h08
  2. Méthode de comparaison 3D
    Par Merel dans le forum Mathématiques
    Réponses: 3
    Dernier message: 09/02/2011, 17h07
  3. Votre opinion sur les méthodes de comparaison de données ?
    Par katanaenmousse dans le forum Débuter
    Réponses: 3
    Dernier message: 15/08/2010, 09h41
  4. méthode virtuelle pure et héritage
    Par Invité dans le forum Langage
    Réponses: 3
    Dernier message: 20/07/2009, 22h12
  5. Méthode abstraite (virtuelle) et héritage
    Par wattman dans le forum Windev Mobile
    Réponses: 0
    Dernier message: 31/03/2009, 15h31

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