Ich bin kein C ++ - Typ, aber ich bin gezwungen, darüber nachzudenken. Warum ist Mehrfachvererbung in C ++ möglich, aber nicht in C #? (Ich kenne das Diamantenproblem , aber das frage ich hier nicht). Wie löst C ++ die Mehrdeutigkeit identischer Methodensignaturen auf, die von mehreren Basisklassen geerbt wurden? Und warum wird dasselbe Design nicht in C # integriert?
c#
c++
language-design
multiple-inheritance
Sandeep
quelle
quelle
Antworten:
Ich denke (ohne einen genauen Bezug zu haben), dass sie in Java die Ausdruckskraft der Sprache einschränken wollten, um das Erlernen der Sprache zu vereinfachen, und weil Code, der Mehrfachvererbung verwendet, häufig zu komplex für das eigene Wohl ist als nicht. Und weil eine vollständige Mehrfachvererbung viel komplizierter zu implementieren ist, hat dies auch die virtuelle Maschine erheblich vereinfacht (die Mehrfachvererbung interagiert besonders schlecht mit dem Garbage Collector, da Zeiger in der Mitte des Objekts (am Anfang der Basis) aufbewahrt werden müssen). )
Und beim Entwerfen von C # haben sie, glaube ich, Java betrachtet und festgestellt, dass die vollständige Mehrfachvererbung in der Tat nicht sehr verfehlt wurde, und beschlossen, die Dinge auch einfach zu halten.
Das tut es nicht . Es gibt eine Syntax zum expliziten Aufrufen der Basisklassenmethode von einer bestimmten Basis, aber es gibt keine Möglichkeit, nur eine der virtuellen Methoden zu überschreiben. Wenn Sie die Methode in der Unterklasse nicht überschreiben, ist es nicht möglich, sie ohne Angabe der Basis aufzurufen Klasse.
Es gibt nichts zu integrieren.
Da Giorgio in Kommentaren die Erweiterungsmethoden der Benutzeroberfläche erwähnt hat, erkläre ich, was Mixins sind und wie sie in verschiedenen Sprachen implementiert sind.
Schnittstellen in Java und C # dürfen nur Methoden deklarieren. Die Methoden müssen jedoch in jeder Klasse implementiert werden, die die Schnittstelle erbt. Es gibt jedoch eine große Klasse von Schnittstellen, bei denen es nützlich wäre, Standardimplementierungen einiger Methoden in Bezug auf andere bereitzustellen. Allgemeines Beispiel ist vergleichbar (in Pseudo-Sprache):
Der Unterschied zur vollständigen Klasse besteht darin, dass diese keine Datenelemente enthalten kann. Es gibt verschiedene Möglichkeiten, dies umzusetzen. Offensichtlich ist Mehrfachvererbung eine. Die Implementierung der Mehrfachvererbung ist jedoch ziemlich kompliziert. Aber hier wird es nicht wirklich gebraucht. Stattdessen implementieren viele Sprachen dies, indem sie das Mixin in eine Schnittstelle aufteilen, die von der Klasse implementiert wird, und ein Repository von Methodenimplementierungen, die entweder in die Klasse selbst injiziert werden oder eine Zwischenbasisklasse generiert und dort platziert werden. Dies ist in Ruby und D implementiert, wird in Java 8 implementiert und kann manuell in C ++ unter Verwendung des seltsamerweise wiederkehrenden Schablonenmusters implementiert werden . Das obige sieht in CRTP-Form so aus:
und wird verwendet wie:
Hierfür muss nichts als virtuelle Basisklasse deklariert werden. Wenn also die Schnittstelle in Vorlagen verwendet wird, bleiben nützliche Optimierungsoptionen offen. Beachten Sie, dass dies in C ++ wahrscheinlich immer noch als zweites übergeordnetes Element vererbt wird. In Sprachen, die keine Mehrfachvererbung zulassen, wird es jedoch in die einzelne Vererbungskette eingefügt
Die Compiler-Implementierung kann den virtuellen Versand möglicherweise vermeiden oder nicht.
In C # wurde eine andere Implementierung ausgewählt. In C # sind die Implementierungen statische Methoden mit vollständig separater Klasse, und die Methodenaufrufsyntax wird vom Compiler entsprechend interpretiert, wenn keine Methode mit dem angegebenen Namen vorhanden ist, aber eine "Erweiterungsmethode" definiert ist. Dies hat den Vorteil, dass Erweiterungsmethoden zu bereits kompilierten Klassen hinzugefügt werden können und den Nachteil, dass solche Methoden nicht überschrieben werden können, um beispielsweise eine optimierte Version bereitzustellen.
quelle
Die Antwort ist, dass es in C ++ bei Namespace-Konflikten nicht richtig funktioniert. Sieh das . Um das Aufeinandertreffen von Namespaces zu vermeiden, müssen Sie alle möglichen Bewegungen mit Zeigern ausführen. Ich habe bei MS im Visual Studio-Team gearbeitet und zumindest teilweise die Delegation entwickelt, um die Kollision von Namespaces insgesamt zu vermeiden. Vorweg hatte ich gesagt, dass sie Schnittstellen auch als Teil der Mehrfachvererbungslösung betrachteten, aber ich habe mich geirrt. Interfaces sind erstaunlich und können in C ++, FWIW zum Laufen gebracht werden.
Die Delegierung befasst sich speziell mit Namespace-Kollisionen: Sie können an 5 Klassen delegieren, und alle 5 von ihnen exportieren ihre Methoden als First-Class-Mitglieder in Ihren Bereich. Äußerlich betrachtet ist dies Mehrfachvererbung.
quelle