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 :

Question sur l'héritage multiple


Sujet :

C++

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 6
    Points : 4
    Points
    4
    Par défaut Question sur l'héritage multiple
    Bonjour,

    Voici mon schéma de classe cible :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
       A
     /   \
    B    C
      \ /  \
       D   E
    Afin d'avoir un A unique au niveau de D, j'ai recours à de l'héritage virtuel :

    Class A
    Class B : public virtual A
    Class C : public virtual A
    Class D : public B, C
    Class E : public C

    Du coup au niveau de E, j'ai des pbs de compilation, notamment au niveau du constructeur où j'initialise la mère (C) ; il me dit qu'il faut aussi que j'initialise A.

    >> error C2512: 'A::A' : no appropriate default constructor available

    Pourriez-vous me conseiller sur ces déclarations de classes au vu de mon schéma cible ? Merci

  2. #2
    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 ce devrait être D qui hérite virtuellement de B et C et non B et C qui héritent virtuellement de A. Il faut dire que je n'ai jamais encore eu de structure en diamant et donc n'est jamais eu recours a l'héritage virtuel. Un conseil : vérifie.

  3. #3
    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
    Salut,
    Cela est lié à l'ordre d'appel des constructeurs : F.A.Q. : Dans quel ordre sont construits les différents composants d'une classe ?
    Ta classe A ne doit pas avoir de constructeur par défaut mais uniquement des constructeurs avec paramètres. Il faut donc préciser au niveau de D quel constructeur tu souhaites appeler (ceux préciser au niveau B et C ne sont pas pris en compte, logique puisque tu veux qu'une seule instance de A par l'héritage virtuel et donc tu dois préciser comment construire cette instance) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    A::A(...):D(...),B(..),C(..)..{...}

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Salut,
    Citation Envoyé par 3DArchi Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    A::A(...):D(...),B(..),C(..)..{...}
    Tu as du confondre, c'est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    D::D(...):A(...),B(...),C(...{}
    C'est D qui hérite de B et de C et ces deux derniers qui héritent de A
    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

  5. #5
    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
    Citation Envoyé par koala01 Voir le message
    Salut,
    Tu as du confondre, c'est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    D::D(...):A(...),B(...),C(...{}
    C'est D qui hérite de B et de C et ces deux derniers qui héritent de A
    Oui.Merci pour la rectification.

  6. #6
    Candidat au Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 6
    Points : 4
    Points
    4
    Par défaut
    OK merci je comprends mieux.
    Par contre du coup je trouve ca infernal de devoir répéter sur chaque
    sous-classe l'initialisation de A.

    Voyez-vous une meilleure façon de procéder ?

    Voici un exemple complet :

    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
    //      A 
    //     / \
    //    B   C
    //     \ / \
    //      D   E
    //      |
    //      F
     
    class A
    {
        public:
            int i;
            A( int j );
    };
    A::A( int j )
    {
    }
     
    class B : public virtual A
    {
        public:
            B( int j );
    };
    B::B( int j ) : A( j )
    {
    }
     
    class C : public virtual A
    {
        public:
            C( int j );
    };
    C::C( int j ) : A( j )
    {
    }
     
    class D : public B, public C
    {
        public:
            D( int j );
    };
    D::D( int j ) : C( j ), B( j ), A( j )
    {
    }
     
    class E : public C
    {
        public:
            E( int j );
    };
    E::E( int j ) : C( j ), A( j )
    {
    }
     
    class F : public D
    {
        public:
            F( int j );
    };
    F::F( int j ) : D( j ), A( j )
    {
    }
     
    int main(int argc, char* argv[])
    {
     
        A a( 1 );
        B b( 2 );
        C c( 3 );
        D d( 4 );
        E e( 5 );
        F f( 6 );
     
    	return 0;
    }

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    De manière générale, lorsqu'un héritage multiple fini en "losange de la mort", c'est souvent le symptôme d'un problème de conception à la base.

    Peut être devrais tu déjà te poser la question de l'opportunité réelle de faire hériter B ET C de a et / ou de faire hériter D de B ET de C

    Il ne faut, en effet, pas oublier que l'héritage public représente une relation EST-UN et qu'il n'a donc de sens que si tu peux, effectivement, dire en toute bonne fois en respectant la sémantique qu'un objet du type dérivé EST-UN objet de la classe de base.

    Le principe de substitution de Liskov te permet d'apporter une partie de la réponse à cette question

    Mais il est particulièrement difficile de juger de l'opportunité d'un héritage lorsque l'on parle d'un cas trop abstrait, car elle doit s'évaluer... au cas par cas.

    Si tu nous donnais un exemple plus concret (ce que représentent et ce que tu attend des différentes classes), nous pourrions surement t'orienter de manière beaucoup plus juste et précise

    [EDIT]Pour la petite histoire, C++ accepte l'héritage public et les risques qu'il implique uniquement pour ne pas "brider l'imagination du développeur", au risque de le laisser se "tirer une balle dans le pied"... Ce n'est pas pour rien si d'autres langages ont, carrément, décidé de l'empêcher
    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
    Candidat au Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 6
    Points : 4
    Points
    4
    Par défaut
    J'ai envie de te donner un cas d'école qui se rapproche du miens

    A = vehicule (couleur)
    B = voiture a essence (couleur, reservoir d'essence)
    C = voiture electrique (couleur, batterie electrique)
    D = véhicule à moteur hybride (couleur, reservoir d'essence, batterie electrique)

    comment penses tu que je pourrais faire autrement?
    (par exemple en Java, comment ca se ferait)

    merci bcp pour ton aide

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Déjà, la motorisation n'est qu'un "détail d'implémentation" de la voiture, qui, elle, est un véhicule

    Une voiture hibride n'est donc pas une voiture à essence "couplée" à une voiture électrique, mais, bel et bien une "voiture" ayant une motorisation double

    tu pourrais donc avoir une hiérarchie "moteur" qui serait 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
    class Moteur
    {
        /* ce qui est intéressant */
    };
    class MoteurEssence : public Moteur
    {
        /* Ce qui est propre au moteur à essence */
    };
    class MoteurElectrique : public Moteur
    {
        /* Ce qui est propre au moteur électrique */
    };
    /* pourquoi pas ??? */
    class MoteurNucleaire : public Moteur
    {
        /* ce qui est propre au moteur nucléaire  */
    };
    A l'extrême limite, tu pourrais prévoir pou chaque type de moteur une classe d'interface qui n'expose d'un point de vue du véhicule (est-ce seulement une voiture :question) que ce qui est propre au moteur en question
    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
    class MotorisableEssence
    {
        public:
            MotorisableEssence(MoteurEssence const & m):m_(m){}
            virtual ~MotorisabelEssence() = 0;
            bool needFuel() const{return m_.reservoireVide();}
        private:
            MoteurEssence m_;
    };
    class MotorisableElectrique
    {
        public:
            MotorisableElectrique(MoteurElectrique const & m):m_(m){}
            virtual ~MotorisableElectrique() = 0;
            bool needCharge() const{return m_.batterieVide();}
    };
    /*...*/
    Ensuite, tu aurais une hiérarchie de classes qui te permet de gérer les différents types de véhicules.
    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
     
    class Vehicule
    {
        /* ce qui est commun à tous les véhicules */
    };
    class Voiture : public Vehicule
    {
        /* ce qui est propre aux voiture, mais commun quelle que soit
         * la motorisation
         */
    };
    class VoitureEssence : public Voiture,
                           public MotorisableEssence
    {
    };
    class VoitureElectrique : public Voiture,
                              public MotorisableElectrique
    {
    };
    class VoitureHybride : public voiture,
                           public MotorisableEssence,
                           public MotorisableElectrique
    {
    };
    De cette manière, chaque hiérarchie peut évoluer de manière tout à fait séparée et distincte, même si l'invention d'une nouvelle motorisation provoquera sans doute fatalement la création de... trois nouvelles classes ( le moteur, l'interface qui l'utilise et... la voiture qui hérite l'interface )

    Cette approche serait sans doute utilisable dans la plupart des langages OO
    [EDIT]Tu pourrais éventuellement envisager de faire hériter VoitureHybride de VoitureEssence ou de voitureElectrique (selon les caractéristiques que tu veux mettre en avant) et de MotorisableElectrique ou de MotorisableEssence (en fonction de l'autre héritage)

    Mais il est généralement préférable de garder les niveaux d'héritages des hiérarchies aussi "bas que possible" (préférer avoir des classes soeurs à des classes enfant de classes enfants )
    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

  10. #10
    Candidat au Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 6
    Points : 4
    Points
    4
    Par défaut
    Merci bcp pour cet exemple détaillé.

    C'est vrai qu'un cas générique avec des A, B ... est un mauvais point de vue puisque par définition, il n'est pas possible de découpler les différents aspects des classes.

    Je vais voir comment repenser mon schéma donc, merci encore.

  11. #11
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Pour ta question sur l'initialisation de A, c'est justement une conséquence de l'héritage virtuel. Celuic-i indique que ce sera à la classe la plus dérivé d'initialiser A et pas forcément à la classe que tu es en train d'écrire, donc je ne vois pas de méthode simple (et qui reste dans l'idée d'une structure polymorphique) pour éviter de répéter cette initialisation.

    @koala: Un langage OO qui interdit l'héritage publique ca existe ? Comment il fait le polymorphisme ? (langage ducked-type à part)

  12. #12
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    @koala: Un langage OO qui interdit l'héritage publique ca existe ? Comment il fait le polymorphisme ? (langage ducked-type à part)
    Je crois que le clavier de koala a fourché et qu'il voulait dire multiple et pas public .

  13. #13
    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 qu'il existe des cas où le losange de la mort se justifie :

    Par exemple, si on souhaite créer un Qfilm (je ne sait pas si Qt en propose un ou pas) on pourrait vouloir le faire hérité de QSound et QWidget qui héritent de QObject donc, on retrouverait un losange.

    Je ne pense donc pas, que le losange de la mort est toujours un problème de conception, mais qu'il est souvent mal utilisé.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    @koala: Un langage OO qui interdit l'héritage publique ca existe ? Comment il fait le polymorphisme ? (langage ducked-type à part)
    Citation Envoyé par white_tentacle Voir le message
    Je crois que le clavier de koala a fourché et qu'il voulait dire multiple et pas public .


    Bien vu... c'est effectivement mon clavier qui a fourché

    Citation Envoyé par NoIdea Voir le message
    Il me semble qu'il existe des cas où le losange de la mort se justifie :

    Par exemple, si on souhaite créer un Qfilm (je ne sait pas si Qt en propose un ou pas) on pourrait vouloir le faire hérité de QSound et QWidget qui héritent de QObject donc, on retrouverait un losange.

    Je ne pense donc pas, que le losange de la mort est toujours un problème de conception, mais qu'il est souvent mal utilisé.
    Le fait est que l'on peut déjà se demander si l'héritage de QObject se justifie.

    Il y a eu récemment un long débat sur l'intérêt des super objet / god object, et, personnellement, je ne suis toujours par persuadé de son opportunité

    Tu remarquera d'ailleurs que la plupart des langages qui interdisent l'héritage multiple utilisent, justement, un super objet, à moins qu'on ne le voie dans l'autre sens : parce qu'ils utilisent un super objet, les langages interdisent l'héritage multiple pour, justement, éviter d'en arriver au losange de la mort
    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
    Responsable Qt & Livres


    Avatar de dourouc05
    Homme Profil pro
    Ingénieur de recherche
    Inscrit en
    Août 2008
    Messages
    26 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur de recherche
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2008
    Messages : 26 655
    Points : 188 665
    Points
    188 665
    Par défaut
    Citation Envoyé par NoIdea Voir le message
    Par exemple, si on souhaite créer un Qfilm (je ne sait pas si Qt en propose un ou pas) on pourrait vouloir le faire hérité de QSound et QWidget qui héritent de QObject donc, on retrouverait un losange.
    AMHA, c'ets un mauvais exemple. En effet, un QFilm représente un film : je le vois plutôt comme la bande que l'on transmet au cinéma. Ensuite, il te faut un widget pour afficher ce film, un QFilmWidget : le couple bâche de projection/projecteur. Aussi, un film n'est pas un son, un film comporte une bande son : ton QFilm aurait deux parties, une pour les données vidéo, une pour les données audio (QSound). Ce ne serait qu'une manière plaisante de rassembler les deux, de les démultiplexer ou quelque chose du genre. Donc, dans cette vision, ce serait un problème de conception.
    Vous souhaitez participer aux rubriques Qt (tutoriels, FAQ, traductions) ou HPC ? Contactez-moi par MP.

    Créer des applications graphiques en Python avec PyQt5
    Créer des applications avec Qt 5.

    Pas de question d'ordre technique par MP !

Discussions similaires

  1. Questions sur l'héritage multiple
    Par beegees dans le forum C++
    Réponses: 12
    Dernier message: 31/03/2008, 17h01
  2. Question sur l'héritage (débutant en C++)
    Par beegees dans le forum C++
    Réponses: 19
    Dernier message: 30/03/2008, 14h45
  3. petite question sur l'héritage et les cast
    Par baedal dans le forum Langage
    Réponses: 3
    Dernier message: 29/02/2008, 00h48
  4. Questions sur l'héritage dans Matisse
    Par Cassios dans le forum NetBeans
    Réponses: 8
    Dernier message: 14/03/2007, 23h23
  5. Question sur l'héritage
    Par the big ben 5 dans le forum Delphi
    Réponses: 28
    Dernier message: 06/06/2006, 17h27

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