web-dev-qa-db-fra.com

Pourquoi l'héritage multiple n'est-il pas autorisé en Java ou en C #?

Je sais que l'héritage multiple n'est pas autorisé en Java et en C #. Beaucoup de livres disent simplement que l'héritage multiple n'est pas autorisé. Mais cela peut être implémenté en utilisant des interfaces. Rien n'est discuté sur les raisons pour lesquelles cela n'est pas autorisé. Quelqu'un peut-il me dire précisément pourquoi ce n'est pas permis?

100

La réponse courte est: parce que les concepteurs de langage ont décidé de ne pas le faire.

Fondamentalement, il semblait que les concepteurs .NET et Java n'autorisaient pas l'héritage multiple car ils estimaient que l'ajout de MI ajoutait trop de complexité aux langages tout en fournissant trop peu d'avantages.

Pour une lecture plus amusante et approfondie, certains articles sont disponibles sur le Web avec des interviews de certains des concepteurs de langues. Par exemple, pour .NET, Chris Brumme (qui a travaillé chez MS sur le CLR) a expliqué les raisons pour lesquelles ils ont décidé de ne pas:

  1. Différentes langues ont en réalité différentes attentes quant à la manière dont MI travaux. Par exemple, comment sont les conflits résolu et si les bases en double sont fusionnés ou redondants. Avant nous pouvons mettre en œuvre MI dans le CLR, nous devons faire une enquête de toutes les langues, figure les concepts communs, et décider comment les exprimer en langue neutre. Nous aimerions aussi doivent décider si MI appartient à le CLS et ce que cela signifierait pour langues qui ne veulent pas de ce concept (vraisemblablement VB.NET, par exemple). De Bien sûr, c'est le métier dans lequel nous sommes en tant que langage d'exécution commun, mais nous ne pas avoir le temps de le faire pour MI encore.

  2. Le nombre d'endroits où MI est vraiment approprié est en fait assez petit. Dans de nombreux cas, plusieurs l'héritage d'interface peut obtenir le travail fait à la place. Dans d'autres cas, vous pouvez être capable d'utiliser encapsulation et délégation. Si nous devions ajouter un construction légèrement différente, comme mixins, serait-ce réellement plus puissant?

  3. L'héritage à plusieurs implémentations ajoute beaucoup de complexité au la mise en oeuvre. Cette complexité impacts coulée, mise en page, expédition, accès au champ, sérialisation, identité comparaisons, vérifiabilité, réflexion, génériques, et probablement beaucoup d'autres endroits.

Vous pouvez lire l'article entier ici.

Pour Java, vous pouvez lire cet article :

Les raisons pour omettre plusieurs héritage du langage Java proviennent principalement du but "simple, orienté objet, et familier". Comme un langage simple, les créateurs de Java voulait un langage que la plupart des développeurs pourrait saisir sans beaucoup entraînement. À cette fin, ils ont travaillé pour rendre le langage similaire au C++ en tant que possible (familier) sans porter sur la complexité inutile de C++ (simple). 

Selon les concepteurs, plusieurs l'héritage cause plus de problèmes et confusion qu'il résout. Alors ils ont coupé héritage multiple de la langue (juste comme ils coupent l'opérateur surcharge). La vaste gamme de designers L’expérience C++ leur a appris que l'héritage multiple ne valait tout simplement pas le mal de tête.

133
Razzie

L'héritage multiple de implementation est ce qui n'est pas autorisé. 

Le problème est que le compilateur/runtime ne peut pas déterminer quoi faire si vous avez une classe Cowboy et une classe Artist, les deux avec des implémentations pour la méthode draw () et que vous essayez ensuite de créer un nouveau type CowboyArtist. Que se passe-t-il lorsque vous appelez la méthode draw ()? Quelqu'un est-il mort dans la rue ou avez-vous une belle aquarelle?

Je crois que cela s'appelle le problème de double héritage diamant.

90
duffymo

Raison: Java est très populaire et facile à coder, en raison de sa simplicité.

Alors, quels que soient les développeurs Java qui se sentent difficiles et compliqués à comprendre pour les programmeurs, ils ont essayé de l'éviter. Un tel type de propriété est l'héritage multiple.

  1. Ils ont évité les pointeurs
  2. Ils ont évité l'héritage multiple.

Problème d'héritage multiple: Problème de diamant.

Exemple

  1. Supposons que la classe A utilise une méthode fun (). la classe B et la classe C proviennent de la classe A.
  2. Et les classes B et C remplacent la méthode fun ().
  3. Supposons maintenant que la classe D hérite à la fois des classes B et C. (hypothèse juste)
  4. Créer un objet pour la classe D.
  5. D d = nouveau D ();
  6. et essayez d'accéder à d.fun (); => appellera-t-il fun () de la classe B ou fun () de la classe C? 

C'est l'ambiguïté qui existe dans le problème du diamant.

Il n’est pas impossible de résoudre ce problème, mais cela crée plus de confusion et de complexité pour le programmeur lorsqu’il le lit Cela cause plus de problème qu’il ne tente de résoudre.

Note : Mais de toute façon, vous pouvez toujours implémenter plusieurs héritages indirectement en utilisant des interfaces.

19
user1923551

Parce que Java a une philosophie de conception très différente de C++. (Je ne vais pas discuter de C # ici.)

En concevant C++, Stroustrup souhaitait inclure des fonctionnalités utiles, indépendamment de la manière dont elles pourraient être utilisées à mauvais escient. Il est possible de perdre du temps avec l'héritage multiple, la surcharge d'opérateur, les modèles et diverses autres fonctionnalités, mais il est également possible de faire de très bonnes choses avec eux.

La philosophie de conception de Java consiste à mettre l'accent sur la sécurité dans les constructions de langage. Le résultat est qu'il y a des choses beaucoup plus délicates à faire, mais vous pouvez être beaucoup plus confiants que le code que vous consultez signifie ce que vous pensez qu'il fait.

De plus, Java était dans une large mesure une réaction de C++ et de Smalltalk, les langages OO les plus connus. Il existe de nombreux autres langages OO (Common LISP était en fait le premier à être standardisé), avec différents systèmes OO qui gèrent mieux les MI.

Sans oublier qu'il est tout à fait possible de faire de l'IM en Java, en utilisant des interfaces, une composition et une délégation. C'est plus explicite qu'en C++, et donc plus maladroit à utiliser, mais vous obtiendrez quelque chose que vous aurez plus de chance de comprendre à première vue.

Il n'y a pas de bonne réponse ici. Il existe différentes réponses et celle qui convient le mieux à une situation donnée dépend des applications et des préférences individuelles.

13
David Thornley

La raison principale (bien que ce ne soit en aucun cas la seule) que les gens s'éloignent de MI est le prétendu "problème du diamant" qui crée une ambiguïté dans votre mise en œuvre. Cet article de wikipedia en discute et explique mieux que moi. MI peut également conduire à un code plus complexe, et de nombreux OO concepteurs prétendent que vous n'avez pas besoin de MI et que si vous l'utilisez, votre modèle est probablement erroné. Je ne suis pas sûr d’être d’accord avec ce dernier point, mais garder les choses simples est toujours un bon plan.

12
Steve Haigh

En C++, l'héritage multiple était un problème majeur lorsqu'il était utilisé de manière incorrecte. Pour éviter ces problèmes de conception courants, plusieurs interfaces "héritage" ont été forcées dans les langages modernes (Java, C #).

8
inazaruk

L'héritage multiple est

  • difficile à comprendre 
  • difficile à déboguer (par exemple, si vous mélangez des classes de plusieurs frameworks comportant des méthodes identiques portant des noms identiques, des synergies assez inattendues peuvent se produire)
  • facile à mal utiliser
  • pas vraiment que utile
  • difficile à mettre en œuvre, surtout si vous voulez le faire correctement et efficacement

Par conséquent, il peut être considéré comme un choix judicieux de pas d'inclure plusieurs héritages dans le langage Java.

8
mfx

Une autre raison est que l'héritage unique rend le casting trivial, n'émettant aucune instruction d'assembleur (autre que la vérification de la compatibilité des types, le cas échéant). Si vous avez plusieurs héritages, vous devez déterminer où commence un parent dans la classe enfant. La performance est donc certainement un avantage (même si ce n’est pas le seul).

5
Blindy

Le chargement dynamique des classes rend difficile la mise en œuvre de l'héritage multiple.

En Java, ils ont plutôt évité la complexité de l'héritage multiple en utilisant un héritage et une interface uniques. La complexité de l'héritage multiple est très élevée dans une situation comme celle décrite ci-dessous

problème de diamant de l'héritage multiple. Nous avons deux classes B et C héritant de A. Supposons que B et C redéfinissent une méthode héritée et fournissent leur propre implémentation. Maintenant, D hérite de l'héritage multiple de B et C. D devrait hériter de cette méthode surchargée, jvm ne peut pas décider quelle méthode surchargée sera utilisée?

En c ++, les fonctions virtuelles sont utilisées pour gérer et nous devons le faire explicitement.

Cela peut être évité en utilisant des interfaces, il n'y a pas de corps de méthode. Les interfaces ne peuvent pas être instanciées - elles ne peuvent être implémentées que par des classes ou étendues par d'autres interfaces.

4
sujith s

À l’époque des années 70, lorsque l’informatique était davantage une science qu’une production en masse, les programmeurs avaient le temps de réfléchir à une bonne conception et à une bonne mise en œuvre. Les produits (programmes) étaient donc de haute qualité (par exemple, la conception TCP/IP). et mise en œuvre). .__ De nos jours, lorsque tout le monde programme et que les responsables modifient les spécifications avant les dates limites, il est difficile de suivre des problèmes aussi subtils que celui décrit dans le lien wikipedia de Steve Haigh; par conséquent, "l'héritage multiple" est limité par la conception du compilateur. Si vous l'aimez, vous pouvez toujours utiliser C++ .... et avoir toute la liberté que vous souhaitez :) 

4
Cata Lin

Je prends la déclaration que "l'héritage multiple n'est pas autorisé en Java" avec une pincée de sel.

L'héritage multiple est défini lorsqu'un "type" hérite de plusieurs "types". Et les interfaces sont également classées en tant que types car ils ont un comportement. Donc, Java a plusieurs héritages. Juste que c'est plus sûr.

4
Rig Veda

En réalité, l'héritage multiple surgira si les classes héritées ont la même fonction. c'est-à-dire que le compilateur aura une confusion qu'il faudra choisir (problème de diamant). Donc, en Java, cette complexité a été supprimée et a donné une interface permettant d’obtenir des fonctionnalités similaires à celles offertes par plusieurs héritages. Nous pouvons utiliser l'interface 

3
Jinu

Java a un concept, à savoir un polymorphisme. Il existe 2 types de polymorphisme en Java. Il y a surcharge de méthode et méthode surchargée. Parmi ceux-ci, la méthode est surchargée avec les relations entre super et sous-classes. Si nous créons un objet d'une sous-classe et invoquons la méthode de superclasse, et si la sous-classe étend plusieurs classes, quelle méthode de super classe doit être appelée?

Ou, tout en appelant le constructeur de la super-classe par super(), quel constructeur de la classe supérieure sera appelé?

Cette décision est impossible avec les fonctionnalités actuelles de l'API Java. donc l'héritage multiple n'est pas autorisé en Java.

2
Abhay Kokate

L'héritage multiple n'est pas autorisé directement en Java, mais il est autorisé via les interfaces.

Raison 

Héritage multiple: Introduit plus de complexité et d'ambiguïté.

Interfaces: Les interfaces sont des classes totalement abstraites en Java qui vous permettent de définir de manière uniforme la structure ou le fonctionnement interne de votre programme à partir de son interface publique, avec pour conséquence une plus grande flexibilité et un code réutilisable. ainsi que plus de contrôle sur la façon dont vous créez et interagissez avec d’autres classes. 

Plus précisément, il s’agit d’une construction spéciale en Java avec la caractéristique supplémentaire qui vous permet d’effectuer une sorte d’héritage multiple, c’est-à-dire des classes pouvant être converties en amont vers plus d’une classe.

Prenons un exemple simple.

  1. Supposons qu'il existe 2 super-classes de classes A et B avec les mêmes noms de méthodes mais des fonctionnalités différentes. En suivant le code avec (étend) mot-clé, l'héritage multiple n'est pas possible.

       public class A                               
         {
           void display()
             {
               System.out.println("Hello 'A' ");
             }
         }
    
       public class B                               
          {
            void display()
              {
                System.out.println("Hello 'B' ");
              }
          }
    
      public class C extends A, B    // which is not possible in Java
        {
          public static void main(String args[])
            {
              C object = new C();
              object.display();  // Here there is confusion,which display() to call, method from A class or B class
            }
        }
    
  2. Mais à travers les interfaces, avec (implémente) le mot-clé, l'héritage multiple est possible.

    interface A
        {
           // display()
        }
    
    
     interface B
        {
          //display()
        }
    
     class C implements A,B
        {
           //main()
           C object = new C();
           (A)object.display();     // call A's display
    
           (B)object.display(); //call B's display
        }
    }
    
1

Quelqu'un peut-il me dire précisément pourquoi ce n'est pas permis?

Vous pouvez trouver une réponse dans cette documentation link

L'une des raisons pour lesquelles le langage de programmation Java ne vous permet pas d'étendre plus d'une classe est d'éviter les problèmes d'héritage multiple d'état, qui est la possibilité d'hériter des champs de plusieurs classes.

Si l'héritage multiple est autorisé et que vous créez un objet en instanciant cette classe, cet objet héritera des champs de toutes les super classes de la classe. Cela causera deux problèmes.

  1. Et si les méthodes ou les constructeurs de différentes super-classes instanciaient le même champ?

  2. Quelle méthode ou quel constructeur aura la priorité?

Même si l'héritage multiple d'état est maintenant autorisé, vous pouvez toujours implémenter 

Héritage multiple de type: capacité d'une classe à implémenter plusieurs interfaces.

Héritage multiple de l'implémentation (via les méthodes par défaut des interfaces): possibilité d'hériter des définitions de méthodes de plusieurs classes

Reportez-vous à cette question SE associée pour des informations supplémentaires:

Ambiguïté d'héritage multiple avec interface

0
Ravindra babu

En C++, une classe peut hériter (directement ou indirectement) de plusieurs classes, appelées héritage multiple .

C # et Java, cependant, limitent les classes à single inheritance, chaque classe hérite de D'une classe parent unique.

L'héritage multiple est un moyen utile de créer des classes qui combinent les aspects de deux hiérarchies de classes disparates Cela se produit souvent lors de l'utilisation de différents cadres de classe au sein d'une même application

Par exemple, si deux frameworks définissent leurs propres classes de base pour les exceptions, vous pouvez utiliser plusieurs héritages pour créer des classes d'exception pouvant être utilisées avec l'un ou l'autre framework.

Le problème avec l'héritage multiple est qu'il peut conduire à une ambiguïté. L'exemple classique est celui où Une classe hérite de deux autres classes, chacune héritant de la même classe:

class A {
    protected:
    bool flag;
};
class B : public A {};
class C : public A {};
class D : public B, public C {
    public:
    void setFlag( bool nflag ){
        flag = nflag; // ambiguous
    }
};

Dans cet exemple, le membre de données flag est défini par class A. Mais class D descend du class B Et du class C, qui dérivent tous deux de A. Donc, par essence, deux copies de flag sont disponibles car deux instances De A sont dans la hiérarchie de D. Lequel voulez-vous définir? Le compilateur se plaindra Que la référence à flag dans D est ambiguous. Un correctif consiste à désambiguïser explicitement la référence:

B::flag = nflag;

Une autre solution consiste à déclarer B et C en tant que virtual base classes, ce qui signifie qu’une seule copie de A can Existe dans la hiérarchie, éliminant ainsi toute ambiguïté.

D'autres complexités existent avec l'héritage multiple, telles que l'ordre dans lequel les classes de base sont initialisées lors de la construction d'un objet dérivé ou la manière dont les membres peuvent être masqués par inadvertance des classes dérivées. Pour éviter ces complexités, certaines langues se limitent au modèle plus simple à héritage unique.

Bien que cela simplifie considérablement l'héritage, cela limite également son utilité Car seules les classes ayant un ancêtre commun peuvent partager des comportements. Les interfaces atténuent quelque peu cette restriction En permettant aux classes de différentes hiérarchies d’exposer des interfaces communes, même si Si elles ne sont pas implémentées par le partage de code.

0
zerocool