Java lässt die Mehrfachvererbung aus dem Grund aus, dass das Designziel, die Sprache einfach zu halten, umgangen wird .
Ich frage mich, ob Java (mit seinem Ökosystem) wirklich "einfach" ist. Python ist nicht komplex und mehrfach vererbt. Also ohne zu subjektiv zu sein, ist meine Frage ...
Was sind die typischen Problemmuster, die von einem Code profitieren, der so konzipiert ist, dass er vielfache Vererbung nutzt?
multiple-inheritance
Baumkodierer
quelle
quelle
Antworten:
Vorteile:
Nachteile:
In C ++ ist ein gutes Beispiel für die Mehrfachvererbung, mit der orthogonale Features zusammengesetzt werden, wenn Sie CRTP verwenden , um beispielsweise ein Komponentensystem für ein Spiel einzurichten.
Ich habe angefangen, ein Beispiel zu schreiben, aber ich denke, ein Beispiel aus der realen Welt ist es wert, angeschaut zu werden. Ein Teil des Ogre3D-Codes verwendet die Mehrfachvererbung auf eine nette und sehr intuitive Art und Weise. Beispielsweise erbt die Mesh- Klasse sowohl von Resources als auch von AnimationContainer. Ressourcen machen die allen Ressourcen gemeinsame Schnittstelle verfügbar, und AnimationContainer macht die Schnittstelle verfügbar, die für die Bearbeitung einer Reihe von Animationen spezifisch ist. Sie sind nicht miteinander verwandt, daher ist es einfach, sich ein Mesh als Ressource vorzustellen, die zusätzlich eine Reihe von Animationen enthalten kann. Fühlt sich natürlich an, nicht wahr?
Sie können sich andere Beispiele in dieser Bibliothek ansehen , z. B. die Art und Weise , wie die Speicherzuweisung auf eine abgestimmte Weise verwaltet wird, indem Klassen von Varianten einer CRTP-Klasse geerbt werden, die neu überladen und gelöscht werden.
Wie bereits erwähnt, ergeben sich die Hauptprobleme bei der Mehrfachvererbung aus der Vermischung verwandter Konzepte. Dadurch muss die Sprache komplexe Implementierungen festlegen (siehe die Art und Weise, wie C ++ mit dem Diamond-Problem spielt ...), und der Benutzer ist sich nicht sicher, was in dieser Implementierung passiert. Lesen Sie beispielsweise diesen Artikel, in dem erläutert wird, wie er in C ++ implementiert ist .
Wenn Sie es aus der Sprache entfernen, vermeiden Sie, dass Personen, die nicht wissen, wie die Sprache dazu gezwungen wird, die Dinge zu verschlechtern. Aber es zwingt zu einer Denkweise, die sich manchmal nicht natürlich anfühlt, selbst wenn es Randfälle sind, kommt es öfter vor, als Sie vielleicht denken.
quelle
Es gibt ein Konzept namens Mixins , das in dynamischeren Sprachen häufig verwendet wird. Mehrfachvererbung ist eine Möglichkeit, mit der Mixins von einer Sprache unterstützt werden können. Mixins werden im Allgemeinen als Methode für eine Klasse verwendet, um verschiedene Funktionalitäten zu akkumulieren. Ohne Mehrfachvererbung müssen Sie Aggregation / Delegation verwenden, um das Verhalten von Mixin-Typen mit einer Klasse zu erhalten, die etwas syntaktisch anspruchsvoller ist.
quelle
Ich denke, die Wahl basiert hauptsächlich auf Problemen aufgrund des Diamantenproblems .
Darüber hinaus ist es häufig möglich, die Verwendung der Mehrfachvererbung durch Delegation oder auf andere Weise zu umgehen.
Ich bin mir nicht sicher, was deine letzte Frage bedeutet. Aber wenn es "in welchen Fällen ist Mehrfachvererbung sinnvoll?" Ist, dann in allen Fällen, in denen Sie ein Objekt A mit Funktionen der Objekte B und C haben möchten.
quelle
Ich werde hier nicht weiter darauf eingehen, aber Sie können die Mehrfachvererbung in Python sicher über den folgenden Link verstehen : http://docs.python.org/release/1.5.1p1/tut/multiple.html :
...
Dies ist nur ein kleiner Absatz, aber groß genug, um die Zweifel, die ich denke, auszuräumen.
quelle
Ein Ort, an dem Mehrfachvererbung nützlich wäre, ist eine Situation, in der eine Klasse mehrere Schnittstellen implementiert, Sie jedoch einige Standardfunktionen in jede Schnittstelle integrieren möchten. Dies ist nützlich, wenn die meisten Klassen, die eine Schnittstelle implementieren, etwas auf die gleiche Weise tun möchten, aber gelegentlich etwas anderes tun müssen. Sie können jede Klasse mit derselben Implementierung haben, aber es ist sinnvoller, sie an einen Ort zu verschieben.
quelle
Dies ist nur ein Beispiel, das für mich von unschätzbarem Wert ist, um die Sicherheit zu verbessern und die Versuchung zu lindern, kaskadierende Änderungen für Anrufer oder Unterklassen anzuwenden.
Wo ich mehrfache Vererbung für unglaublich nützlich befunden habe, selbst für die abstraktesten, zustandslosen Schnittstellen, ist die nicht-virtuelle Schnittstellen-IDiom (NVI) in C ++.
Sie sind nicht einmal wirklich abstrakte Basisklassen so viel wie Schnittstellen , die nur noch ein wenig Implementierung ihnen die universellen Aspekte ihrer Verträge zu erzwingen, da sie nicht wirklich die Allgemeingültigkeit des Vertrages so viel wie besser verengenden Strafvollzug .
Einfaches Beispiel (einige könnten überprüfen, ob ein übergebenes Dateihandle offen ist oder so ähnlich):
In diesem Fall wird es möglicherweise
f
von tausend Stellen in der Codebasis aufgerufen, währendf_impl
es von hundert Unterklassen überschrieben wird.Es wäre schwierig, diese Art von Sicherheitsprüfung an allen 1000 Orten durchzuführen, die anrufen,
f
oder an allen 100 Orten, die außer Kraft gesetzt werdenf_impl
.Indem ich nur diesen Einstiegspunkt für die Funktionalität nicht-virtuell mache, habe ich einen zentralen Ort, an dem ich diese Prüfung durchführen kann. Und diese Prüfung reduziert die Abstraktion nicht im Geringsten, da sie lediglich eine Voraussetzung für den Aufruf dieser Funktion darstellt. In gewisser Weise stärkt dies den Vertrag, der von der Schnittstelle bereitgestellt wird, und verringert die Belastung durch die Überprüfung der
x
Eingabe, um sicherzustellen, dass sie an allen 100 Stellen, an denen sie außer Kraft gesetzt wird, den gültigen Voraussetzungen entspricht.Ich wünschte, jede Sprache hätte und wünschte sich auch in C ++, dass es sich eher um ein natives Konzept handelt (z. B .: Wir müssten keine separate Funktion zum Überschreiben definieren).
Dies ist äußerst nützlich, wenn Sie dies nicht
assert
im Voraus getan haben und festgestellt haben, dass Sie es später benötigen, wenn an zufälligen Stellen in der Codebasis negative Werte übergeben werdenf
.quelle
Erstens: Mehrere Kopien der Basisklasse (ein C ++ - Problem) und enge Kopplung zwischen Basis- und abgeleiteten Klassen.
Zweitens: Mehrfachvererbung von abstrakten Schnittstellen
quelle