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 :

Héritage multiple : Pour ou contre


Sujet :

C++

  1. #1
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut Héritage multiple : Pour ou contre
    Citation Envoyé par icer Voir le message
    L'héritage multiple est, en générale, à éviter.
    Bof, je ne vois vraiment pas pourquoi...
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  2. #2
    Membre averti Avatar de icer
    Inscrit en
    Janvier 2006
    Messages
    332
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 332
    Points : 363
    Points
    363
    Par défaut
    Bof, je ne vois vraiment pas pourquoi...
    Tout simplement parceque ça n'est pas une bonne conception : surtout lorsqu'il y a des noms de membres communs dans les supers classes. Comment savoir quels membres vient de quelles classes.

    Un exemple trés simple :

    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
    class A{
      int i;
    };
     
    class B{
      int i;
    };
     
    class C : A, B{
      int j;
    };
     
    C unC;
     
    unC.i = 5; // Est-ce le i hérité de A ou celui hérité de B ?
    C'est la même chose pour les méthodes.

    Je le répéte : une conception avec de l'héritage multiple n'est pas une conception saine.

    Il y a un cas où l'héritage multiple peut-être judicieux : lorsqu'on effectue une conception avec des interfaces, comme en java... dans les autres cas c'est fortement déconseillé. (sauf si on veut s'arracher les cheveux )

  3. #3
    Membre expérimenté
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Points : 1 452
    Points
    1 452
    Par défaut
    Bonsoir,

    Citation Envoyé par icer Voir le message
    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
    class A{
      int i;
    };
     
    class B{
      int i;
    };
     
    class C : A, B{
      int j;
    };
     
    C unC;
     
    unC.i = 5; // Est-ce le i hérité de A ou celui hérité de B ?
    Justement le compilateur n'autorise pas ça.
    On peut y parvenir si le membre est dans une classe de base commune.


    Citation Envoyé par icer Voir le message
    Il y a un cas où l'héritage multiple peut-être judicieux : lorsqu'on effectue une conception avec des interfaces, comme en java... dans les autres cas c'est fortement déconseillé. (sauf si on veut s'arracher les cheveux )
    J'utilise l'héritage multiple pour une interface GUI (avec SDL), et c'est tellement utile dans ce domaine que j'ai du mal à croire qu'il n'est pas utile autre part.

  4. #4
    Membre averti Avatar de icer
    Inscrit en
    Janvier 2006
    Messages
    332
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 332
    Points : 363
    Points
    363
    Par défaut
    J'utilise l'héritage multiple pour une interface GUI (avec SDL), et c'est tellement utile dans ce domaine que j'ai du mal à croire qu'il n'est pas utile autre part.
    Si ta bibliothéque de GUI est bien conçue, je peux te croire que c'est bien pratique. Le problème avec le c++ c'est qu'il ne différencit pas syntaxiquement un héritage d'une implémentation d'interface (ce que java fait). En c++ c'est au programmeur de faire la différence, donc à prendre plus de précaution avec l'héritage multiple, voir même l'éviter...

  5. #5
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    J'ai eu à travailler pas mal ces derniers temps avec un langage qui permet l'héritage multiple d'interface, mais pas l'héritage multiple en général (C# en l'occurrence), et je peux te dire que le manque d'héritage multiple m'a conduit à écrire du code bien plus sale (avec duplication et tout) que si j'en avais eu.

    Désolé de ne pouvoir décrire plus le problème ici (après tout, je ne suis pas proprio du code en question, et puis ça prendrait du temps à décrire). En particulier, j'aurais pu dans ce cas obtenir un résultat satisfaisant sans héritage multiple, mais il m'aurait fallu pour ça réorganiser les responsabilités autrement dans la hiérarchie de classes, et ça je ne pouvais pas le faire, car il s'agit de classes issues d'une bibliothèques externe. Avec l'héritage multiple, le problème était résolu en 2 lignes.

    Je ne dis pas que l'héritage multiple (dans sa version complète) s'utilise tous les jours, dans toutes les hiérarchies de classes, mais je dis qu'il y a des cas où il est utile, et que dans ces cas, les alternatives sont beaucoup moins satisfaisantes.

    Et je n'ai pas encore vu d'arguments qui expliqueraient en quoi l'héritage multiple serait problématique (à par que c'est plus difficile à implémenter, ce qu'en tant qu'utilisateur du langage, je n'ai rien à faire).
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  6. #6
    Membre averti Avatar de icer
    Inscrit en
    Janvier 2006
    Messages
    332
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 332
    Points : 363
    Points
    363
    Par défaut
    ... mais il m'aurait fallu pour ça réorganiser les responsabilités autrement dans la hiérarchie de classes...
    L'héritage multiple t'a permis de "rattraper" une mauvaise conception de la bibliothèque... c'est plus pour une raison pratique que pour une raison de conception.

    Et je n'ai pas encore vu d'arguments qui expliqueraient en quoi l'héritage multiple serait problématique (à par que c'est plus difficile à implémenter, ce qu'en tant qu'utilisateur du langage, je n'ai rien à faire).
    Lors de la conception : on peut identifier exactement 4 types de relation entre classes :

    - IS A : est un
    - HAS A : a un , est composé d'un
    - USES A : utilise un, communique avec un ...
    - BEHAVES AS A : se comporte en tant que

    L'héritage est implémenté uniquement pour "IS A" et "BEHAVES AS A".
    Et dans le cas de "BEHAVES AS A", il s'agit d'interface, qui en c++ est implémenté grâce à l'héritage multiple.

  7. #7
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par icer Voir le message
    L'héritage multiple t'a permis de "rattraper" une mauvaise conception de la bibliothèque... c'est plus pour une raison pratique que pour une raison de conception.
    Elle n'était pas mauvaise en tant que telle. Elle n'était juste pas adaptée à mon besoin. Il n'est pas possible de faire un truc qui convienne à tout le monde. Mon besoin était de combiner deux aspects existants et indépendants d'une bibliothèque existante.

    Et je n'aurais pas pu le faire en refactorant la bibliothèque tout en la laissant indépendante de mon code : j'aurais pu le faire uniquement en introduisant des concepts spécifiques à mon code au sein de la bibliothèque. Ce qui n'est pas un bon design. En gros, J'avais A et B dans la bibliothèque, B dérivant de A. dans mon code, j'avais C, qui dérivait de A, et D, que j'aurais aimé faire dériver de C et B. La "solution" à héritage simple aurait consisté à avoir l'arborescence A<-C<-B<-D, mais du coup, il n'existait plus de class B générique et autonome dans la bibliothèque.

    Voir par exemple http://archive.eiffel.com/doc/manual.../multiple.html pour d'autres arguments en faveur de l'héritage multiple, avec lesquels je suis assez d'accord.

    Citation Envoyé par icer Voir le message
    Lors de la conception : on peut identifier exactement 4 types de relation entre classes :

    - IS A : est un
    - HAS A : a un , est composé d'un
    - USES A : utilise un, communique avec un ...
    - BEHAVES AS A : se comporte en tant que
    Tant qu'on ne défini pas plus précisément ces termes, j'ai du mal à faire des discussions fines sur eux. Ma définition de IS-A est la suivante :
    B IS-A A ssi, dans chaque fonction qui a été conçue pour prendre en paramètre un objet de type A, on peut à la place passer un objet de type B, et obtenir un comportement correct.
    Je n'ai pas de définition pour BEHAVES-AS.
    J'attends tes définitions pour poursuivre la discussion.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  8. #8
    Membre averti Avatar de icer
    Inscrit en
    Janvier 2006
    Messages
    332
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 332
    Points : 363
    Points
    363
    Par défaut
    Nous avons la même définition de IS-A.

    En ce qui concerne BEHAVE-AS-A, il s'agit d'une relation avec la même propriété que tu as définis. Cependant, elle est moins forte.

    Je vais prendre un exemple pour imager la chose:

    Une relation IS-A : un Aigle est un Oiseau
    Une autre relation IS-A : un Avion est un Véhicule

    Ici nous avons deux classes, même si elle n'héritent pas de la même classe de base, elles sont toutes les deux un comportement en commun qui est voler().

    On peut définir une interface se nommant "QuiVole" avec une méthode voler(), et sa relation avec les deux autres classes serait de type BEHAVES-AS-A :
    Un Aigle se comporte comme un QuiVole
    Un Avion se comporte comme un QuiVole

    Le problème en C++ est que les interfaces n'existent pas syntaxiquement. Mais on peut les définir comme étant des classes abstraites, sans données membres et possédant uniquement des méthodes virtuelles pures.

    Le programmeur qui implémente une telle conception doit faire la différence entre ces deux types de relations même si elle s'écrivent exactement de la même manière : un héritage.

    En java, par exemple, la distinction est claire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public class Aigle extends Oiseau implements QuiVole{
    ...
    }
    La même chose en C++
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class Aigle : public Oiseau, public QuiVole{
    ...
    };
    Je soutiens l'idée que l'héritage multiple en C++ doit être utiliser uniquement dans le cas d'implémentations d'interfaces.

  9. #9
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Je soutiens pour ma part que la distinction entre extend et implement en Java (ou entre IS-A et BEHAVES-AS-A) est artificielle et n'existe que pour contourner un manque du langage : L'absence d'héritage multiple.

    En outre, pour moi, une interface bien faite DOIT contenir du code : Le code de test qui valide les pré et post conditions de la fonction de l'interface, et qui ne DOIT pas varier selon la classe qui implémente l'interface. Une interface peut aussi contenir d'autre code, comme par exemple du code d'instrumentation.

    Reprenons ton exemple, et définissons un peu plus l'interface QuiVole. Si je l'écris en Java (ne pas faire attention à la syntaxe, je ne connais pas Java, c'est pour l'idée) :

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    interface QuiVole
    {
      float longitude();
      float latitude();
      float altitudeEnM();
      float altitudeEnPieds();
    };

    Et la version C++ (ne pas faire attention à la syntaxe, je connais le C++, mais je suis fainéant et c'est juste pour l'idée ) :
    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
    class QuiVole
    {
    public:
      float longitude() {return doLongitude();}
      float latitude() {return doLatitude();}
      float altitudeEnM() 
      {
        float altitude = doAltitude();
        assert(estAuDessusDuSol(altitude, latitude(), longitude()));
        return altitude;
      }
      float altitudeEnPieds() {return altitudeEnM * M_TO_PIEDS;}
    private:
      virtual float doLongitude() = 0;
      virtual float doLatitude() = 0;
      virtual float doAltitude() = 0;
      bool (estAuDessusDuSol(float, float, float);
    };
    Quand on compare les deux versions, on se rend compte que la version "riche" de l'interface :
    - Sépare clairement les fonctions destinées à l'utilisateur de QuiVole de celles destinées à un implémenteur d'objet QuiVole, alors que ces deux aspects de l'interface sont mélangés en Java.
    - Défini et valide un contrat sur l'altitude, que toutes les classes dérivées devront respecter.
    - Evite les duplications de code qu'il y aurait
    - soit dans toutes les classes dérivées entre altitudeEnM et altitudeEnPieds, la relation entre ces deux fonctions ne pouvant pas varier d'une classe dérivée à l'autre,
    - soit dans le code utilisateur si on décidait de ne garder dans l'interface qu'une seule de ces deux fonctions.

    Le dernier point n'est pas théorique : Dans mon code en C#, je retrouve assez régulièrement cet idiome : Deux classes implémentent la même interface, mais comme on n'a pas pu mettre de code au niveau de l'interface, et qu'on ne veut pas le dupliquer, on crée une autre classe dans laquelle on a une fonction statique qui reprend ce code (on lui passe les paramètres qui vont bien) et dans chacune des implémentations de l'interface, on duplique un appel vers cette fonction statique. C'est lourd, et ça n'apporte rien à la lisibilité, bien au contraire.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  10. #10
    Membre confirmé
    Avatar de NewbiZ
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2002
    Messages
    184
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2002
    Messages : 184
    Points : 563
    Points
    563
    Par défaut
    De ce que j'ai pu ressentir, les philosophies C++ et Java sont vraiment différentes sur ce point.

    En Java, on parle d'une interface en terme de comportement/contrainte à gérer/respecter et de classe abstraite en terme de services à rendre.

    Si vous connaissez le Smalltalk, pour vérifier que deux objets se comportent (BEHAVE-AS) de la même facon, on comparerait non pas leur type (ce qui comparerait IS), mais leur protocole (les messages auxquels ils répondent).
    L'héritage n'est qu'une des solutions d'implémenter la notion de BEHAVE-AS-A. Autrement dit, le fait que deux classes qui se comportent pareil soient dans la même hiérarchie de classes en C++ n'est qu'un effet de bord du langage.
    En Ruby par exemple ce n'est pas le cas. Le langage étant plus laxiste, on se contente de fixer quelques règles de nommage pour les méthodes.
    Pour tester une relation IS, on utiliserait ainsi is_of?, et pour BEHAVE-AS on utiliserait respond_to?.

    L'interface correspond donc à la notion de BEHAVE-AS-A en java: on veut assurer que d'une capacité à réagir à certaines demandes, dans un certain contexte.
    On aura donc des Iterable : l'objet peut agir comme un conteneur séquentiel, des Displayable : l'objet peut agir comme quelquechose d'affichable, des Immutable : l'objet peut garantir sa non-modification, Comparable : ces objets peuvent être comparés, etc...

    L'héritage utilisé ici n'a rien à voir avec celui utilisé dans le cadre d'une relation IS-A. C'est en fait très lié à ce qu'on apelle le "duck typing", plus répandu dans les langages dynamiques: "Je me fiche de ce que c'est réellement, tant que ca fait coincoin quand je lui demande, alors c'est un canard".

    Pour s'en convaincre, il suffit de regarder le source d'une interface standard en Java, prenons Comparable. De tête, ca doit ressembler à quelquechose comme ca:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    interface Comparable
    {
      int comparateTo( Object inst, Object other );
    }
    Comparable n'a qu'une seule vocation: placer une contrainte sur le nom de la fonction chargée de la comparaison.

    En java, on considère donc qu'un objet n'a qu'une seule nature portée par son héritage "extends", mais qu'il peut se comporter de multiples facons, porté par son héritage "implements".
    Ce genre de distinction n'est pas habituel en C++. Je soupçonne que ce soit parceque le langage est beaucoup plus riche en mécanismes d'instauration de contraintes:
    Pas besoin de Comparable en C++, il y a la surcharge d'opérateurs.
    Pas besoin de Immutable en C++, il suffit de suffixer les méthodes par un const.
    Etc..

    Bon après, je ne suis pas spécialiste de java, je n'en fait qu'en cours, donc tout ce que je dis là, ce n'est que ce que j'ai pu ressentir de ce langage à travers mes ptits yeux de jeune programmeur C++

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 625
    Points : 30 671
    Points
    30 671
    Par défaut
    Salut
    Citation Envoyé par icer Voir le message
    Tout simplement parceque ça n'est pas une bonne conception : surtout lorsqu'il y a des noms de membres communs dans les supers classes. Comment savoir quels membres vient de quelles classes.
    Personnellement, je ne vois pas pourquoi il s'agirait d'une mauvaise conception...

    Après tout, la méthode UML autorise tout à fait d'y faire appel, et si on peut déconseiller dans certains d'y faire appel, c'est généralement pour la cause:
    certains langages (java par exemple) ne l'autorisent pas... il faut donc pour ces langages faire le choix entre la pérennité de la conception en concevant de manière tout à fait indépendante du langage ou une conception adaptée plus adaptée au langage mais dont la pérennité est moins garantie
    citation de mémoire tirée tout droit d'un bouquin bien coté sur le site sur la conception UML en java...

    L'hértiage est à utiliser quand on peut peut sémantiquement parlant dire qu'un objet de la classe dérivée est un objet de la classe de base et que la suppression des caractéristiques de la classe de base rendent la classe dérivée non viable (comprendre "non viable comme" le fait qu'il commence à lui manquer des caractéristiques importantes)

    Ainsi un chien est un mammifère, et si tu lui retire les caractéristiques qui en font un mammifère, ou qui en font un animal (car un mammifère est un animal), le type ne peut plus rendre les services de base.

    De la même manière une voiture est un véhicule, et si tu retire les caractéristiques qui font le "véhicule", ton objet n'est plus en mesure de rendre les services de base.

    Enfin, s'il est sémantiquement correct de considérer qu'un turbo-générateur est une turbine et que c'est un générateur - car il n'est pas possible de dire qu'il s'agit d'une turbine disposant d'un générateur ni l'inverse, et que les caractéristiques de l'un dépendent fortement des caractéristiques de l'autre - pourquoi ne pas utiliser l'héritage multiple avec une turbine et un générateur, alors que la méthode de conception ET le langage l'autorisent

    Bien sur, comme de nombreuses autres possibilités offertes en programmation, il s'agit d'être particulièrement prudent lorsque l'on décide d'avoir recours à l'héritage multiple...

    Et ce d'autant plus si on en arrive à un arbre d'héritage dit "en losange", voir, "en diamant" (c'est à dire où les différentes classes qui servent pour l'héritage ont un ancêtre commun)

    Il est, bien sur, possible d'éviter le recours à l'héritage multiple, mais si pour ce faire, il faut en arriver à multiplier le nombre de classes par deux ou à augmenter le temps de conception dans la même mesure, il est peut être utile de décider d'utiliser toutes les possibilités offertes par les méthodes de conception et par le langage
    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

  12. #12
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par NewbiZ Voir le message
    L'héritage utilisé ici n'a rien à voir avec celui utilisé dans le cadre d'une relation IS-A. C'est en fait très lié à ce qu'on apelle le "duck typing", plus répandu dans les langages dynamiques: "Je me fiche de ce que c'est réellement, tant que ca fait coincoin quand je lui demande, alors c'est un canard".
    Pour moi, un des intérêts principaux du duck typing, c'est de pouvoir aisément utiliser en tant que colvert et sans la modifier une classe qui ne connaissait pas la notion de colvert au moment où elle a été écrite, pour peu qu'elle ait été écrite en utilisant certaines conventions de nommage.

    Si la notion d'interface est du duck typing, alors c'est : "Je me fiche de ce que c'est réellement, tant que ca fait coincoin quand je lui demande, et que de toute façon, je sais dès le départ que c'est un canard, alors c'est un canard"
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  13. #13
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    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 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Si on devait rejeter l'héritage multiple parce que des gens ne savent pas s'en servir, alors on devrait rejeter l'héritage tout court parce que ces même gens ne savent pas s'en servir. Que de fois j'ai vu le LSP bafoué. Quand cette notion n'est pas comprise, qu'il y ait 50 ou 1 héritage ne change rien, le design est pourri et finira par nous coincer.

    Sinon, comme Loïc j'ai également été élevé au James (si je puis dire ^^'), et l'héritage multiple de contrats est un énorme avantage offert par l'héritage multiple non bridé. Rien que pour cela, cette fonctionnalité n'est pas à bannir.

    Pour ce qui est du IComparable, j'attribue la différence essentiellement à deux faits:
    - Le Java ne supporte pas la sémantique de valeur aussi proprement (ou supporte pas tout court?) que le C++ ; chez lequel mélanger héritage et sémantique de valeur est suicidaire
    - Le C++ a un typage plus précis, à la limite duck-typing, quand on veut écrire des TAD. L'arrivée des concepts rendra la chose plus propre.
    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...

  14. #14
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Personnellement je ne me rappelle pas avoir eu besoin d'héritage multiple autrement que pour l'implémentation de multiples interfaces.
    Ce qui me chagrine dans l'héritage multiple, c'est surtout que c'est pas performant, et se limiter aux interfaces ne résout aucunement le problème à ce que je sache.
    Boost ftw

  15. #15
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Il m'est arrivé récemment une chose étrange, où l'héritage multiple m'a été très utile. C'est dans une application un peu complexe (un jeu), avec des classes assez abstraites, par exemple des classes qui se contente d'implémenter un algorithme, des classes qui représentent certains objets qui existent déjà, mais d'une autre manière afin d'améliorer les performances sur certains traitements, etc.

    Et je me suis retrouvé dans un cas où j'avais besoin d'ajouter des fonctionnalités dans une classe (disons A), mais ces fonctionnalités existaient déjà dans une autre classe (disons B) qui n'avait cependant rien à voir. Ce que j'ai fait: j'ai sorti de B les fonctions dont j'avais besoin dans une nouvelle classe C, je l'ai aggrégé à B, et j'en ai fait hériter A. Du coup A hérite de 2 classe parce qu'elle héritait déjà d'une autre classe.

    Au début je trouvais ça un peu risqué, brouillon. D'autant plus que j'aurais pu faire une aggregation, mais ça me plaisait moins car dans mon cas, l'héritage facilitait une implémentation qui assurait une gestion propre des ressources (RAII). Et puis finalement, au fur et à mesure des ajouts et de la maturation de cette application, je trouve que cet héritage multiple est fort pratique et finalement pas si dangereux que ça. Et maintenant je l'utilise ailleurs.

    Par exemple pour l'affichage graphique: j'ai un objet qui hérite de la classe Displayable (classe qui contient les données et les fonctions nécessaires à l'affichage) et de Serializable (classe qui fournit les fonctions, les données et l'interface pour plusieurs types de sérialisations dont j'ai besoin dans ñom appli). Au final, je ne vois pas où est le danger.

    Seulement il est vrai que dans mon cas, on s'approche de la programmation par interface, à ceci près que mes interfaces implémentent déjà des fonctionnalités.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  16. #16
    screetch
    Invité(e)
    Par défaut
    Citation Envoyé par loufoque Voir le message
    Ce qui me chagrine dans l'héritage multiple, c'est surtout que c'est pas performant, et se limiter aux interfaces ne résout aucunement le problème à ce que je sache.
    performant dans quel sens ?

  17. #17
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Ben t'as un pointeur de vtable par classe héritée, l'upcasting nécessite de réaligner, etc.
    Boost ftw

  18. #18
    screetch
    Invité(e)
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    class C : public A, public B
    sizeof(C) == sizeof(A)+sizeof(B)
    quant a additionner un chiffre a un autre, je ne dis pas que c'est l'operation la plus rapide d'un cpu, mais bon. chipoter sur les cycles, ca va 5 minutes.

  19. #19
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par screetch Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    class C : public A, public B
    sizeof(C) == sizeof(A)+sizeof(B)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sizeof C <= sizeof(A) + sizeof(B) + e
    e pouvant a priori être non nul pour des contraintes d'alignement, plus d'autres chose que j'oublie peut-être.

    Mon < vient du cas suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class A : public virtual Base
    {
    };
     
    class B : public virtual Base
    {
    };
    Maintenant, je suis d'accord pour dire que dans la plupart des domaines d'application, je ne pense pas que le surcout de l'héritage multiple soit sensible.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  20. #20
    screetch
    Invité(e)
    Par défaut
    je vais reformuler

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class A;
    class B;
     
    class C1
    {
      A a;
      B b;
    };
     
    class C2 : public A, public B
    {
    };
     
    sizeof(C1) == sizeof(C2);
    merci pour la remarque =)

Discussions similaires

  1. Arguments pour et contre Access ?
    Par bottura dans le forum Sondages et Débats
    Réponses: 240
    Dernier message: 23/03/2018, 23h25
  2. Pour ou contre l'Open source ?
    Par Thcan dans le forum Débats sur le développement - Le Best Of
    Réponses: 317
    Dernier message: 01/05/2008, 15h06
  3. Héritage multiple pour les ATL
    Par groovyroe dans le forum Visual C++
    Réponses: 1
    Dernier message: 10/08/2007, 14h02
  4. [XML Schemas]héritage multiple
    Par nicolas_jf dans le forum XML/XSL et SOAP
    Réponses: 2
    Dernier message: 10/06/2003, 12h55

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