Frage von davidhoff, 45

Java Mehrfachvererbung nicht unterstützt, warum C++ dagegen schon?

Guten Abend,

Ich lerne momentan Java, und bin auf das Diamond-Problem zugestoßen.

Ich verstehe dass Java das Problem vermeiden möchte. Da eine Klasse(d) zwei Unterklassen(b,c) von einer Oberklasse(a) erben möchte, gibt's dort ein Problem z.B. mit der Methodenaufruf. Denn der Compiler weiß nicht welche Methode die Klasse(d) aufrufen möchte.

C++ hat zwei Lösungen: Diamond-Vererbung, Normale Mehrfachvererbung (Quelle: https://de.wikipedia.org/wiki/Diamond-Problem)

Ich Versteh nicht ganz genau wie C++ das Problem mit der beiden Lösungen löst und warum nutzt Java nicht solche Lösungen wie bei C++?

PS: Und ich weiß dass es bei Java Schnittstellen gibt, die das Problem umgeht, aber trotzdem warum nicht wie bei C++?

Vielen Dank im Voraus :)

Antwort
von PeterKremsner, 30

Das ganze hat einfach etwas mit dem Design der Sprache zu tun.

C++ baut im wesentlichen auf Pointern auf Funktionen auf, du hast also Merfachvererbung dadurch implementiert, dass ein Pointer auf eine Funktion überschrieben werden kann, das geht auch mehrmals hintereinander.

Bei Java würde so etwas auch funktionieren und mit C++.Net zeigt Microsoft dass es auch in einer Managed Language ohne direkte Pointer geht.

Java hat aber einfach diese Designeinstellung übernommen und gesagt eine Klasse kann nur von einer Unterklasse erben, wenn von mehreren Klassen geerbt werden soll, soll man den Umweg über Interfaces gehen.

Warum das so Implementiert wurde weiß ich nicht, aber vermutlich einfach weil es von den Entwicklern als schlechter Programmierstil betrachtet wurde ähnlich wie die Verwendung von goto.

Java hat aber in manchen Dingen auch komische Eigenheiten, es werden zB keine Unsigned Datentypen unterstützt, was gerade wenn man aus dem C/C++ bereich kommt, am Anfang als sehr hinderlich angesehen wird.

Kommentar von davidhoff ,

Achso verstehe. Dankeschön. :)

Expertenantwort
von TeeTier, Community-Experte für programmieren, 13

Bei dem Thema brechen regelmäßig Religionskriege aus, deshalb gehe ich jetzt nicht ins Detail, nur so viel:

  1. Mehrfachvererbung ist KEIN Problem, und zwar in keiner Sprache. Es gibt immer Mittel und Wege, das Diamantenproblem zu umschiffen. (In C++ z. B. sehr elegant mit "using" und in Java z. B. mit manueller Überladung ... gibt aber noch mehr Möglichkeiten!)
  2. Java bietet bei Interfaces neuerdings "Default Methods" an, was im Grunde nichts anderes als Mehrfachvererbung inkl. Diamantenproblem ist.
  3. Selbst ohne Default-Methoden gab es das "Problem" der Mehrfachvererbung auch schon immer in Java, kam halt nur immer darauf an, was man daraus macht. (bei "extends" Kompilierfehler, bei "implements" mit gleicher Signatur kein Problem)
  4. Mir persönlich scheint es so, als ob sich Java nicht sicher ist, was es denn nun eigentlich will. Sowohl Einfach- als auch Mehrfachvererbung haben ihre Vor- UND Nachteile. Allerdings sollte man auch zu einer der beiden Seiten stehen, und nicht unsicher hin und her wanken. (In zukünftigen Java-Versionen sind übrigens noch weitere Aufweichungen des Interface-Designs geplant. Mal sehen was uns da blüht.)
  5. Beide Sprachen (C++ und Java) unterstützen unterschiedliche Konzepte. Man kann mit beiden gut arbeiten, wenn man sich strikt daran hält. (C++ bietet hier deutlich mehr Freiraum als Java!)

Zu guter Letzt sei noch erwähnt, dass du des öfteren über den sinngemäßen Spruch stolpern wirst, dass "Java seine Entwickler wie Kinder behandelt, C++ hingegen wie Erwachsene". Bei aller Liebe zu Java, aber ich glaube, da ist was dran! :)

Schönen Tag noch! :)

PS: Allerdings hat C++ genauso seine Inkonsistenzen und Widersprüche! Man muss halt lernen, mit dem umzugehen, was man zur Verfügung hat.

Wenn eine Sprache Mehrfachvererbung bietet, kann man die auch benutzen ... muss aber nicht. Und wenn eine Sprache dieses Feature nicht bietet, dann muss man sich eben dran gewöhnen. Sterben wird deshalb keiner. Egal wofür er sich entscheidet / entscheiden MUSS. :)

PPS: Um nochmal auf deine eigentliche Frage einzugehen ... es ist einfach eine Designentscheidung, die nur Sun / Oracle beantworten kann. :)

Antwort
von WhiteGandalf, 8

Noch eine Ergänzung: Die Behauptung, die Machbarkeit oder Nichtmachbarkeit von Mehrfachvererbung oder auch nur Vererbung hätte irgendwas mit dem Überschreiben von Pointern zu tun, ist Nonsense. Es ist zwar nicht zufällig, dass in C++ die Vererbung von Funktionen mittels Pointern implementiert ist, weil das auf Maschinenebene das effektivste Verfahren dafür ist, aber das bedeutet mitnichten, dass dies die einzig mögliche Form der Implementierung wäre, noch, dass dies hinderlich oder förderlich bezüglich Mehrfachvererbung wäre.

Java wurde bei seiner Erfindung explizit als Derivat von C++ mit dem Ziel erfunden, viele Konzepte von C++, die aufgrund mangelnder Intelligenz von Anwendungsprogrammierern massenhaft missbraucht und/oder fehlerhaft genutzt wurden, schlicht und ergreifend rauszuschmeißen. Mit dem Ziel, die im Alltag durchschnittlich zu erwartende Fehlerrate zu senken.

Tatsächlich hatte ich in den letzten zwanzig Jahren nicht den Eindruck gewinnen können, dass sich die Fehlerrate von Java-Programmierern signifikant von der von C++-Programmierern unterscheidet. Korrekt ist aber, dass es in Java mitunter sehr viel aufwendiger ist, bestimmte Operationen umzusetzen - sowohl aus Sicht des Programmierers bzw. dessen Gehalts als auch aus Sicht des Prozessors, der den Mist zur Laufzeit des Programms verarbeiten muss.

Hinten heraus kommt, dass man immer mit allen Programmiersprachen (sofern sie nur gewisse Anforderungen an Universalität erfüllen) alles programmieren kann. Einschließlich aller Konzepte. Einschließlich Mehrfachvererbung. Unterschiedlich ist nur, wie weit man dabei NATIV von der Programmiersprache unterstützt wird. Aber sobald man sich eine Bibliothek für irgendein Problem geschrieben hat, relativiert sich das sowieso wieder. Immer.

Kommentar von MalNachgedacht ,

Java wurde bei seiner Erfindung explizit als Derivat von C++ mit dem Ziel erfunden, viele Konzepte von C++, die aufgrund mangelnder Intelligenz von Anwendungsprogrammierern massenhaft missbraucht und/oder fehlerhaft genutzt wurden, schlicht und ergreifend rauszuschmeißen. Mit dem Ziel, die im Alltag durchschnittlich zu erwartende Fehlerrate zu senken.

Ich würde es eher so formulieren, dass man beim Design von Java auf einige eher selten genutzte und/oder fehlerträchtige Konzepte von C++ verzichtet hat - wozu auch Mehrfachvererbung zählt.

Dazu kommt dann auch noch, dass bei Java die Plattformunabhängigkeit besser gewährt sein sollte als bei C++ weswegen man manche "Tricks" aus C++ welche nicht portabel sind per Sprachdesign so gut wie möglich verhindern wollte.

Tatsächlich hatte ich in den letzten zwanzig Jahren nicht den Eindruck gewinnen können, dass sich die Fehlerrate von Java-Programmierern signifikant von der von C++-Programmierern unterscheidet. 

Tausende von Sicherheitslücken in Windows waren letztlich der Pointerarithmetik (und z.B. den daraus möglichen Bufferoverflows) von C++ zu "verdanken".

Kommentar von TeeTier ,

Tausende von Sicherheitslücken in Windows waren letztlich der Pointerarithmetik (und z.B. den daraus möglichen Bufferoverflows) von C++ zu "verdanken".

ALLE Features einer jeden Sprache - ich betone: ALLLLEEE - haben Vor- UND Nachteile. Zu den Nachteilen zählen prinzipbedingt auch Sicherheitsprobleme.

Guck dir mal den Java JIT an! Der Vorteil ist extrem flotter Code und dank Branch-Prediction (anders als im CPU-Cache) erreicht man evtl. sogar eine schnellere Ausführung als bei C++, auch wenn diese Fälle selten sind.

Aaaaber, eine JIT-Technik braucht zwangsläufig auch Schreibzugriff auf das Text-Segment, und reißt somit ungewollt ein scheunentorgroßes Sicherheitsloch auf, welches in dieser Form bei C++ nicht mal ansatzweise existiert.

Das ist übrigens auch DER Hauptgrund, warum Sicherheitslücken in Java so kritisch sind, weil man - mehr oder weniger - wild Shellcode injezieren, und den aktuellen Maschinencode nach Gutdünken modifizieren kann. Die meisten der gängigen Anti-Exploit-Techniken greifen hier überhaupt nicht, auch wenn sie das Betriebssystem unterstützt.

Fazit: Das Argument, C++ Zeiger sind gefährlich, und deshalb erlauben wir jetzt mal vollen Schreibzugriff auf den gesamten Speicher, zieht irgendwie nicht. :)

Würde Java auf JIT verzichten, und stattdessen Pointer unterstützen, wäre es DEFINITIV sicherer, aber auch um Faktoren langsamer!

Da Java aber so ist, wie es ist, musste man also abwägen, zwischen Sicherheit und Geschwindigkeit, und man hat sich für Geschwindigkeit entschieden.

Beides, auf dem hohen Niveau von C++, wird man allein schon wegen des Sprachdesigns, bei Java nicht erreichen können! :)

PS: In den nächsten Jahren werden Intel-CPUs einen Shadow-Stack einführen, was das Problem nicht eliminieren, aber stark vermindern dürfte! Davon profitieren dann aber beide gleich stark: Sowohl C++, als auch Java! :)

Keine passende Antwort gefunden?

Fragen Sie die Community