Warum ist Mehrfachvererbung in Java oder C # nicht zulässig?

Ich weiß, dass Mehrfachvererbung in Java und C # nicht erlaubt ist. Viele Bücher sagen nur, Mehrfachvererbung ist nicht erlaubt. Aber es kann mithilfe von Schnittstellen implementiert werden. Nichts wird darüber diskutiert, warum es nicht erlaubt ist. Kann mir jemand genau sagen, warum das nicht erlaubt ist?

Die kurze Antwort ist: weil die Sprachdesigner entschieden haben, das nicht zu tun.

Grundsätzlich schien es, dass sowohl die .NET- als auch die Java-Designer keine Mehrfachvererbung zuließen, weil sie der Meinung waren, dass das Hinzufügen von MI den Sprachen zu viel Komplexität hinzufügte und gleichzeitig zu wenig Nutzen brachte .

Für mehr Spaß und tiefgründiges Lesen gibt es einige Artikel im Internet mit Interviews von einigen der Sprachdesigner. Für .NET hat Chris Brumme (der bei MS an der CLR gearbeitet hat) erklärt, warum sie sich entschieden haben,

  1. Unterschiedliche Sprachen haben unterschiedliche Erwartungen an die functionsweise von MI. Zum Beispiel, wie Konflikte getriggers werden und ob doppelte databaseen zusammengeführt oder redundant sind. Bevor wir MI in der CLR implementieren können, müssen wir eine Übersicht über alle Sprachen erstellen, die gebräuchlichen Konzepte herausfinden und entscheiden, wie wir sie sprachneutral express können. Wir müssten auch entscheiden, ob MI in das CLS gehört und was dies für Sprachen bedeuten würde, die dieses Konzept nicht haben wollen (zum Beispiel VB.NET). Natürlich ist das das Geschäft, in dem wir uns als gemeinsame Sprachlaufzeit befinden, aber wir haben es noch nicht für MI geschafft.

  2. Die Anzahl der Stellen, an denen MI tatsächlich angebracht ist, ist tatsächlich ziemlich gering. In vielen Fällen kann die inheritance mehrerer Schnittstellen die Aufgabe stattdessen erledigen. In anderen Fällen können Sie möglicherweise Kapselung und Delegierung verwenden. Wenn wir ein etwas anderes Konstrukt wie Mixins hinzufügen würden, wäre das dann tatsächlich stärker?

  3. Die mehrfache Implementierungsvererbung fügt der Implementierung viel Komplexität hinzu. Diese Komplexität beeinflusst Casting, Layout, Versand, Feldzugriff, Serialisierung, Identitätsvergleiche, Überprüfbarkeit, Reflektion, Generika und wahrscheinlich viele andere Orte.

Sie können den vollständigen Artikel hier lesen.

Für Java können Sie diesen Artikel lesen:

Die Gründe für das Weglassen der Mehrfachvererbung aus der Java-Sprache rühren meist vom “einfachen, objektorientierten und vertrauten” Ziel her. Als einfache Sprache wollten die Entwickler von Java eine Sprache, die die meisten Entwickler ohne umfangreiches Training verstehen konnten. Zu diesem Zweck arbeiteten sie daran, die Sprache C ++ so ähnlich wie möglich (vertraut) zu machen, ohne die unnötige Komplexität von C ++ (einfach) zu übernehmen.

Nach Ansicht der Designer verursacht die Mehrfachvererbung mehr Probleme und Verwirrung, als sie triggers. Daher schneiden sie die Mehrfachvererbung aus der Sprache aus (genau wie sie die Überlastung des Operators verringern). Die umfassende C ++ – Erfahrung der Designer hat ihnen gezeigt, dass Mehrfachvererbung die Kopfschmerzen nicht wert war.

Mehrfache inheritance der Implementierung ist was nicht erlaubt ist.

Das Problem ist, dass der Compiler / Runtime nicht herausfinden kann, was zu tun ist, wenn Sie eine Cowboy- und eine Artist-class haben, beide mit Implementierungen für die draw () -Methode, und dann versuchen Sie, einen neuen CowboyArtist-Typ zu erstellen. Was passiert, wenn Sie die draw () Methode aufrufen? Liegt jemand tot auf der Straße oder hast du ein schönes Aquarell?

Ich glaube, dass es das Doppel-Diamant-inheritancesproblem genannt wird.

Grund: Java ist aufgrund seiner Einfachheit sehr beliebt und einfach zu programmieren.

Also, was auch immer Java-Entwickler für Programmierer schwierig und kompliziert zu verstehen, sie versuchten, es zu vermeiden. Eine solche Art von Eigenschaft ist Mehrfachvererbung.

  1. Sie vermieden pointers
  2. Sie vermieden Mehrfachvererbung.

Problem mit Mehrfachvererbung: Diamond-Problem.

Beispiel :

  1. Angenommen, class A hat eine Methode fun (). class B und class C stammen von class A.
  2. Und beide classn B und C überschreiben Methode fun ().
  3. Nehmen wir nun an, dass class D sowohl class B als auch C erbt.
  4. Objekt für class D erstellen
  5. D d = neu D ();
  6. und versuche auf d.fun () zuzugreifen; => wird es class B’s Spaß () oder class C’s Spaß () nennen?

Dies ist die Mehrdeutigkeit, die beim Diamantproblem existiert.

Es ist nicht unmöglich, dieses Problem zu lösen, aber es erzeugt beim Lesen mehr Verwirrung und Komplexität für den Programmierer. Es verursacht mehr Probleme, als es zu lösen versucht.

Hinweis : Sie können die Mehrfachvererbung jedoch immer indirekt über Schnittstellen implementieren.

Weil Java eine völlig andere Designphilosophie als C ++ hat. (Ich werde hier nicht C # diskutieren.)

Bei der Entwicklung von C ++ wollte Stroustrup nützliche functionen hinzufügen, unabhängig davon, wie sie missbraucht werden könnten. Es ist möglich, mit Mehrfachvererbung, Überladen von Operatoren, Vorlagen und verschiedenen anderen functionen in großen Mengen zu scheitern, aber es ist auch möglich, einige sehr gute Dinge mit ihnen zu machen.

Die Java-Designphilosophie soll Sicherheit in Sprachkonstrukten betonen. Das Ergebnis ist, dass es Dinge gibt, die viel schwieriger sind, aber Sie können viel sicherer sein, dass der Code, den Sie betrachten, das bedeutet, was Sie denken.

Außerdem war Java zu einem großen Teil eine Reaktion von C ++ und Smalltalk, den bekanntesten OO-Sprachen. Es gibt viele andere OO-Sprachen (Common Lisp war eigentlich die erste, die standardisiert wurde), mit verschiedenen OO-Systemen, die MI besser handhaben.

Ganz zu schweigen davon, dass es durchaus möglich ist, MI in Java zu verwenden, indem Schnittstellen, Komposition und Delegierung verwendet werden. Es ist expliziter als in C ++, und daher ist es umständlicher zu verwenden, aber es wird Ihnen etwas geben, das Sie auf den ersten Blick besser verstehen.

Hier gibt es keine richtige Antwort. Es gibt unterschiedliche Antworten, und welche für eine gegebene Situation besser ist, hängt von den Anwendungen und individuellen Präferenzen ab.

Der hauptsächliche (wenn auch keineswegs der einzige) Grund, warum Menschen von MI wegsteuern, ist das sogenannte “Diamantproblem”, das zu Mehrdeutigkeit bei der Umsetzung führt. Dieser Wikipedia-Artikel diskutiert und erklärt besser als ich könnte. MI kann auch zu komplexeren Code führen, und viele OO-Designer behaupten, dass du MI nicht brauchst, und wenn du es verwendest, ist dein Modell wahrscheinlich falsch. Ich bin mir nicht sicher, ob ich dem letzten Punkt zustimme, aber die Dinge einfach zu halten ist immer ein guter Plan.

In C ++ war die Mehrfachvererbung ein Hauptproblem, wenn sie nicht ordnungsgemäß verwendet wurde. Um diese populären Design-Probleme zu vermeiden, wurden stattdessen in modernen Sprachen (Java, C #) mehrere Schnittstellen “inheritance” erzwungen.

Mehrfachvererbung ist

  • schwer zu verstehen
  • schwer zu debuggen (wenn Sie beispielsweise classn aus mehreren Frameworks mit identisch benannten Methoden in die Tiefe mischen, können ganz unerwartete Synergien auftreten)
  • leicht zu mißbrauchen
  • nicht wirklich so nützlich
  • schwer zu implementieren, vor allem, wenn Sie es richtig und effizient machen wollen

Daher kann es als eine kluge Entscheidung angesehen werden, keine Mehrfachvererbung in die Java-Sprache aufzunehmen.

Ein weiterer Grund ist, dass die Single-inheritance das Casting trivial macht und keine Assembler-statementen ausgibt (abgesehen von der Prüfung der Kompatibilität der Typen, falls erforderlich). Wenn Sie mehrere inheritanceen haben, müssen Sie herausfinden, wo in der Kindklasse ein bestimmter Elternteil beginnt. performance ist also sicherlich ein Vorteil (obwohl nicht der einzige).

Ich nehme die Aussage, dass “Mehrfachvererbung ist in Java nicht erlaubt” mit einer Prise Salz.

Mehrfachvererbung ist definiert, wenn ein “Typ” von mehr als einem “Typ” erbt. Und Schnittstellen werden auch als Typen klassifiziert, da sie Verhalten haben. Also hat Java mehrere inheritanceen. Nur dass es sicherer ist.

Das dynamische Laden von classn erschwert die Implementierung der Mehrfachvererbung.

In Java vermieden sie tatsächlich die Komplexität der Mehrfachvererbung, indem sie einzelne inheritance und Schnittstelle verwendeten. Die Komplexität der Mehrfachvererbung ist in einer Situation, wie sie nachstehend erläutert wird, sehr hoch

Diamantproblem der Mehrfachvererbung. Wir haben zwei classn B und C, die von A erben. Angenommen, B und C überschreiben eine geerbte Methode und sie stellen ihre eigene Implementierung bereit. Jetzt erbt D sowohl von B als auch von C, die mehrfache inheritance machen. D sollte diese überschriebene Methode erben, kann jvm nicht entscheiden, welche überschriebene Methode verwendet wird?

In C ++ werden virtuelle functionen verwendet und wir müssen dies explizit tun.

Dies kann durch die Verwendung von Schnittstellen vermieden werden, es gibt keine Methodenkörper. Schnittstellen können nicht instanziiert werden – sie können nur durch classn implementiert oder um andere Schnittstellen erweitert werden.

Als die Informatik in den alten Tagen (70er) mehr Wissenschaft und weniger Massenproduktion war, hatten die Programmierer Zeit, über gutes Design und gute Implementierung nachzudenken, und als Ergebnis hatten die Produkte (Programme) eine hohe Qualität (z. B. TCP / IP-Design) und Implementierung). Heutzutage, wenn jeder programmiert und die Manager die Spezifikationen vor Deadlines ändern, sind subtile Probleme wie die, die im Wikipedia-Link von Steve Haigh Post beschrieben werden, schwer zu verfolgen; Daher ist die “Mehrfachvererbung” durch das Compilerdesign begrenzt. Wenn Sie es mögen, können Sie immer noch C ++ verwenden …. und haben Sie alle Freiheit, die Sie wollen 🙂

In Wirklichkeit wird eine Mehrfachvererbung auftreten, wenn die vererbten classn die gleiche function haben. dh der Compiler wird eine Verwirrung haben, die man wählen muss (Diamantproblem). Also in Java diese Komplexität entfernt und gab Schnittstelle, um die functionalität wie Mehrfachvererbung zu erhalten. Wir können die Schnittstelle benutzen

Java hat Konzept, dh Polymorphismus. Es gibt 2 Arten von Polymorphie in Java. Es gibt Methodenüberladung und Methodenüberschreibung. Unter ihnen geschieht das Überschreiben von Methoden mit Super- und Subklassenbeziehungen. Wenn wir ein Objekt einer Unterklasse erstellen und die Methode der Superklasse aufrufen, und wenn die Unterklasse mehr als eine class erweitert, welche Superklassenmethode sollte aufgerufen werden?

Oder, während der Superklassenkonstruktor von super() aufgerufen wird, welcher Superklassenkonstruktor wird aufgerufen?

Diese Entscheidungen sind durch die aktuellen Java-API-functionen nicht möglich. Daher ist Mehrfachvererbung in Java nicht erlaubt.

Mehrfachvererbung ist in Java nicht direkt erlaubt, aber über Schnittstellen ist es erlaubt.

Grund :

Mehrfachvererbung: Führt zu mehr Komplexität und Mehrdeutigkeit.

Interfaces: Interfaces sind vollständig abstrakte classn in Java, die Ihnen eine einheitliche Möglichkeit geben, die Struktur oder die inneren Abläufe Ihres Programms von seiner öffentlich verfügbaren Schnittstelle aus zu beschreiben, mit der Folge einer größeren Flexibilität und wiederverwendbarem Code sowie mehr Kontrolle darüber, wie Sie andere classn erstellen und mit ihnen interagieren.

Genauer gesagt sind sie ein spezielles Konstrukt in Java mit der zusätzlichen Eigenschaft, dass Sie eine Art mehrfache inheritance durchführen können, dh classn, die auf mehr als eine class erweitert werden können.

Nehmen wir ein einfaches Beispiel.

  1. Angenommen, es gibt 2 Superklassen A und B mit denselben Methodennamen, aber unterschiedlichen functionalitäten. Durch folgenden Code mit (erweitertem) Schlüsselwort ist eine mehrfache inheritance nicht möglich.

      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. Aber über Schnittstellen ist mit (implements) keyword multiple inheritance möglich.

     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 } } 

Kann mir jemand genau sagen, warum das nicht erlaubt ist?

Sie können die Antwort über diesen Dokumentationslink finden

Ein Grund, warum die Java-Programmiersprache es nicht erlaubt, mehr als eine class zu erweitern, besteht darin, die Probleme der Mehrfachvererbung von Zuständen zu vermeiden, nämlich die Fähigkeit, Felder aus mehreren classn zu erben

Wenn Mehrfachvererbung zulässig ist und wenn Sie ein Objekt erstellen, indem Sie diese class instanziieren, erbt dieses Objekt Felder aus allen Superklassen der class. Es wird zwei Probleme verursachen.

  1. Was, wenn Methoden oder Konstruktoren aus verschiedenen Superklassen das gleiche Feld instanziieren?

  2. Welche Methode oder welcher Konstruktor hat Vorrang?

Auch wenn die Mehrfachvererbung von Status jetzt erlaubt ist, können Sie dennoch implementieren

Mehrfache inheritance des Typs : Fähigkeit einer class, mehr als eine Schnittstelle zu implementieren.

Mehrfache inheritance der Implementierung (über Standardmethoden in Schnittstellen): Fähigkeit, Methodendefinitionen von mehreren classn zu erben

Weitere Informationen finden Sie in dieser verwandten SE-Frage:

Mehrfache inheritancesmehrdeutigkeit mit Schnittstelle

In C ++ kann eine class (direkt oder indirekt) von mehreren classn erben, was als Mehrfachvererbung bezeichnet wird .

C # und Java begrenzen jedoch classn auf einzelne inheritance, wobei jede class von einer einzelnen Elternklasse erbt.

Die mehrfache inheritance ist eine nützliche Methode zum Erstellen von classn, die Aspekte zweier unterschiedlicher classnhierarchien kombinieren, was häufig bei der Verwendung verschiedener classn-Frameworks in einer einzelnen Anwendung passiert.

Wenn zwei Frameworks beispielsweise ihre eigenen Basisklassen für Ausnahmen definieren, können Sie mithilfe der Mehrfachvererbung Ausnahmeklassen erstellen, die mit beiden Frameworks verwendet werden können.

Das Problem mit Mehrfachvererbung ist, dass es zu Mehrdeutigkeit führen kann. Das klassische Beispiel ist, wenn eine class von zwei anderen classn erbt, von denen jede von derselben class erbt:

 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 } }; 

In diesem Beispiel ist das flag Datenelement durch die class A definiert. Die class D stammt jedoch von der class B und der class C , die beide von A sind. Im Wesentlichen sind also zwei Kopien des flag verfügbar, da zwei Instanzen von A in der classnhierarchie von D . Welchen willst du einstellen? Der Compiler wird sich beschweren, dass der Verweis auf flag in D mehrdeutig ist . Eine Lösung besteht darin, die Referenz explizit zu disambiguieren:

 B::flag = nflag; 

Eine andere Lösung besteht darin, B und C als virtual base classes zu deklarieren, was bedeutet, dass nur eine Kopie von A in der Hierarchie existieren kann, wodurch Mehrdeutigkeiten vermieden werden.

Andere Komplexitäten bestehen bei Mehrfachvererbung, z. B. die Reihenfolge, in der die Basisklassen beim Erstellen eines abgeleiteten Objekts initialisiert werden, oder die Art, in der Mitglieder unbeabsichtigt aus abgeleiteten classn ausgeblendet werden. Um diese Komplexität zu vermeiden, beschränken sich einige Sprachen auf das einfachere Einzelvererbungsmodell.

Obwohl dies die inheritance erheblich vereinfacht, schränkt es auch dessen Nützlichkeit ein, da nur classn mit einem gemeinsamen Vorfahren Verhalten teilen können. Schnittstellen mildern diese Einschränkung etwas, indem sie es ermöglichen, dass classn in verschiedenen Hierarchien gemeinsame Schnittstellen verfügbar machen, selbst wenn sie nicht durch Freigabe von Code implementiert werden.

Stellen Sie sich dieses Beispiel vor: Ich habe eine class Shape1

Es hat CalcualteArea Methode:

 Class Shape1 { public void CalculateArea() { // } } 

Es gibt eine andere class Shape2 , die dieselbe Methode hat

 Class Shape2 { public void CalculateArea() { } } 

Jetzt habe ich eine Kindklasse Circle, die sich sowohl aus Shape1 als auch Shape2 ergibt;

 public class Circle: Shape1, Shape2 { } 

Wenn ich nun ein Objekt für Circle erstelle und die Methode anrufe, weiß das System nicht, welche Methode für den Berechnungsbereich aufgerufen werden soll. Beide haben die gleichen Signaturen. Der Compiler wird also verwirren. Aus diesem Grund sind mehrere Erbschaften nicht erlaubt.

Es kann jedoch mehrere Schnittstellen geben, da Schnittstellen keine Methodendefinition haben. Selbst beide Interfaces haben dieselbe Methode, beide haben keine Implementierung und es wird immer die Methode in der Child-class ausgeführt.