Eine Verwendung für Mehrfachvererbung?


15

Kann jemand an irgendeine Situation denken, um mehrfache Vererbung zu verwenden? Jeder Fall, den ich denken kann, kann durch das Verfahren Operator

gelöst wird
AnotherClass() { return this->something.anotherClass; } 
  0

Hat dies Ihre Frage beantwortet?Wenn ja, bitte akzeptiere eine Antwort. (Tipp: +12 Antwort könnte die Antwort sein) 03 jan. 102010-01-03 12:31:46

21

Die meisten Verwendungen von Full Scale Multiple Vererbung sind für Mixins. Als Beispiel:

class DraggableWindow : Window, Draggable { } 
class SkinnableWindow : Window, Skinnable { } 
class DraggableSkinnableWindow : Window, Draggable, Skinnable { } 

etc ...

In den meisten Fällen ist es am besten Mehrfachvererbung verwenden streng Schnittstelle Vererbung zu tun.

class DraggableWindow : Window, IDraggable { } 

Dann implementieren Sie die IDraggable-Schnittstelle in Ihrer DraggableWindow-Klasse. Es ist viel zu schwer, gute Mix-Klassen zu schreiben. Der Vorteil des MI-Ansatzes (selbst wenn Sie nur Interface MI verwenden) ist, dass Sie alle Arten von Windows als Window-Objekte behandeln können, aber die Flexibilität haben, Dinge zu erstellen, die nicht möglich wären (oder mehr) schwierig) mit einfacher Vererbung.

Zum Beispiel in vielen Klasse-Frameworks sehen Sie so etwas wie dieses:

class Control { } 
class Window : Control { } 
class Textbox : Control { } 

Nun nehmen wir Sie eine Textbox mit Fenstereigenschaften wollte? Wie sein dragable, eine Titelzeile hat, etc ... Sie könnten etwas tun:

class WindowedTextbox : Control, IWindow, ITexbox { } 

Im einzelnen Vererbungsmodell, können Sie nicht einfach erben von beiden Fenstern und Textbox ohne einige Probleme mit mit doppelter Kontrolle Objekte und andere Arten von Problemen. Sie können eine WindowedTextbox auch als Fenster, Textfeld oder Steuerelement behandeln.

Um auch Ihr .anotherClass() - Idiom zu adressieren, gibt .anotherClass() ein anderes Objekt zurück, während Mehrfachvererbung das gleiche Objekt für verschiedene Zwecke verwendet.


12

I Mehrfachvererbung besonders nützlich bei der Verwendung von mixin Klassen finden.

Wie in Wikipedia erklärt:

In der objektorientierten Programmierung Sprachen, ein mixin eine Klasse ist, dass eine bestimmte Funktionalität bietet durch eine Unterklasse sein geerbt, ist aber nicht allein stehen gemeint .

Ein Beispiel für die Verwendung von Mixinklassen in unserem Produkt ist das Speichern und Wiederherstellen von Konfigurationen. Es gibt eine abstrakte Mixin-Klasse, die eine Reihe rein virtueller Methoden definiert. Jede Klasse, die gespeichert werden kann, erbt von der Mix-In-Klasse "Sichern/Wiederherstellen", die ihnen automatisch die entsprechende Funktion zum Speichern/Wiederherstellen gibt.

Sie können jedoch auch von anderen Klassen als Teil ihrer normalen Klassenstruktur erben. Daher ist es üblich, dass diese Klassen in dieser Hinsicht mehrfache Vererbung verwenden.

Ein Beispiel für Mehrfachvererbung:

class Animal 
{ 
    virtual void KeepCool() const = 0; 
} 

class Vertebrate 
{ 
    virtual void BendSpine() { }; 
} 


class Dog : public Animal, public Vertebrate 
{ 
    void KeepCool() { Pant(); } 
} 

Was am wichtigsten ist, wenn jede Form der öffentlichen Vererbung (einzelne oder mehrere) tun, ist die ist ein Beziehung zu respektieren. Eine Klasse sollte nur von einer oder mehreren Klassen erben, wenn sie eines dieser Objekte ist. Wenn es eines dieser Objekte einfach "enthält", sollte stattdessen eine Aggregation oder Zusammensetzung verwendet werden.

Das obige Beispiel ist gut strukturiert, weil ein Hund ein Tier und auch ein Wirbeltier ist.

  0

Das ist keine Mehrfachvererbung. Es ist die Verwendung von Schnittstellen, aber C++ implementiert es einfach auf die gleiche Weise. 21 feb. 092009-02-21 23:57:59

  0

@Erik - Es ist nur eine Schnittstelle, wenn die Mixinklasse vollständig abstrakt ist. In dem Codebeispiel, das ich gab, hat Vertebrate :: BendSpine() eine Implementierung, wenn auch eine leere. Ich würde diese Mehrfachvererbung immer noch nennen, auch wenn es nicht das beste Beispiel ist. 22 feb. 092009-02-22 00:01:18

+1

Wäre es nicht sinnvoller, wenn das Wirbeltier eine Unterklasse des Tieres wäre und wenn der Hund nur Wirbeltiere abwandert? Zuletzt habe ich überprüft, dass alle Wirbeltiere Tiere waren. 22 feb. 092009-02-22 00:18:18

+2

Ein besseres Beispiel wäre FlyingCreature als Mixin. Die meisten Vögel und einige Säugetiere (Fledermäuse) würden sowohl von FlyingCreature als auch von der Basisklasse Bird oder Mammal erben. Ähnlich verhält es sich bei anderen Eigenschaften, die sich auf die übliche Taxonomie auswirken. 22 feb. 092009-02-22 00:28:53

  0

Nicht das beste Beispiel, aber der Punkt steht ... anstatt eine * tiefe * Vererbungsstruktur zu haben, die in vielen Situationen übertrieben ist, können Sie von den gewünschten Elternattributen erben (oder mischen) und das gleiche Ergebnis erhalten. 22 feb. 092009-02-22 00:29:19

  0

@Kibbee - das ist ein guter Punkt. Vielleicht war es nicht das beste Beispiel für Klassenhierarchie, aber es war das Beste, was ich mir vorstellen konnte, als ich die Antwort editierte. Hoffentlich ist mir klar, wie vielfache Vererbung Mixins unterstützt. 23 feb. 092009-02-23 10:09:37


2

Ein Fall, an dem ich kürzlich arbeitete, beinhaltete netzwerkfähige Etikettendrucker. Wir müssen Etiketten drucken, also haben wir eine Klasse LabelPrinter. Diese Klasse enthält virtuelle Aufrufe zum Drucken mehrerer verschiedener Etiketten. Ich habe auch eine generische Klasse für TCP/IP verbundene Dinge, die verbinden, senden und empfangen können. Wenn ich also einen Drucker implementieren musste, erbte er sowohl die LabelPrinter-Klasse als auch die TcpIpConnector-Klasse.


2

Ich denke, fmsf Beispiel ist eine schlechte Idee. Ein Auto ist kein Reifen oder Motor. Sie sollten die Komposition dafür verwenden.

MI (der Implementierung oder Schnittstelle) kann verwendet werden, um Funktionalität hinzuzufügen. Diese werden oft Mixinklassen genannt. Stellen Sie sich vor, Sie haben eine GUI. Es gibt View-Klasse, die Zeichnung und eine Drag & Drop-Klasse behandelt, die Ziehen behandelt. Wenn Sie ein Objekt, das sie sowohl Sie eine Klasse wie

class DropTarget{ 
public void Drop(DropItem & itemBeingDropped); 
... 
} 

class View{ 
    public void Draw(); 
... 
} 

/* View you can drop items on */ 
class DropView:View,DropTarget{ 

} 

0

Das folgende Beispiel haben würden, ist meist etwas, das ich oft in C sehen ++: manchmal kann es aufgrund von Utility-Klassen notwendig sein, die Sie brauchen, sondern wegen ihres Designs kann nicht durch Komposition verwendet werden (zumindest nicht effizient oder ohne den Code noch unordentlicher zu machen als auf mult. Vererbung zurückzugreifen). Ein gutes Beispiel ist eine abstrakte Basisklasse A und eine abgeleitete Klasse B, und B muss auch eine Art serialisierbare Klasse sein, also muss sie von einer anderen abstrakten Klasse namens Serializable abgeleitet sein.Es ist möglich, MI zu vermeiden, aber wenn Serializable nur ein paar virtuelle Methoden enthält und tiefen Zugriff auf die privaten Mitglieder von B benötigt, dann lohnt es sich, den Vererbungsbaum zu murren, um keine Freundendeklarationen zu machen und einigen Zugriff auf die Interna von B zu gewähren Helferzusammensetzungsklasse.


4

Die meisten Menschen verwenden Mehrfachvererbung im Kontext der Anwendung mehrere Schnittstellen zu einer Klasse. Dies ist der Ansatz, den ua Java und C# durchsetzen.

C++ ermöglicht es Ihnen, mehrere Basisklassen ziemlich frei zu verwenden, in einer ist-eine-Beziehung zwischen den Typen. Sie können also ein abgeleitetes Objekt wie jede seiner Basisklassen behandeln.

Eine andere Verwendung, wie LeopardSkinPillBoxHat points out, ist in Mix-Ins. Ein hervorragendes Beispiel hierfür ist die Loki library aus Andrei Alexandrescus Buch Modern C++ Design. Er verwendet, was er ausdrückt Richtlinienklassen, die das Verhalten oder die Anforderungen einer bestimmten Klasse durch Vererbung angeben.

Eine weitere Verwendung ist eine, die einen modularen Ansatz vereinfacht, der API-independence durch die Verwendung von Schwester-Klasse-Delegation in der oft gefürchteten Diamant-Hierarchie ermöglicht.

Die Verwendungen für MI sind viele. Das Missbrauchspotenzial ist noch größer.


4

Java hat Schnittstellen. C++ hat nicht.

Daher kann mehrere Vererbung verwendet werden emulieren die Schnittstelle Feature. Wenn Sie ein C# - und Java-Programmierer sind, können Sie bei jeder Verwendung einer Klasse, die eine Basisklasse erweitert, aber auch einige wenige Schnittstellen implementiert, zugeben, was in manchen Situationen nützlich sein kann.

  0

Dem stimme ich zu :) Das Schlimmste beim Lernen von C++ und später von C# ist die Einschränkung von Mixins. Manchmal finde ich mich selbst mit Copy-Paste und implementiere eine Mixin-Schnittstelle, die für meinen Teil schlechter Code oder Design sein könnte, aber ich kann mir nichts anderes vorstellen - und als Programmierer hasst du Copy-Paste 23 feb. 092009-02-23 20:35:19

  0

C++ emuliert Interfaces 100% mit abstrakten Klassen. Über welches "Feature der Benutzeroberfläche" redest du? Java/C# -Version der Mehrfachvererbung für Schnittstellen? 30 mär. 092009-03-30 19:17:23

  0

C++ hat kein 'interface' Schlüsselwort, da es es nicht benötigt (es hat mehrfache Vererbung). Wenn andere Sprachen wie Java und C# Schnittstellen haben, muss die Mehrfachvererbung in C++ einige Anwendungsfälle haben. 31 mär. 092009-03-31 17:15:35


2

Ich denke, es wäre am nützlichsten für Boilerplate-Code. Beispielsweise ist das IDisposable-Muster für alle .NET-Klassen identisch. Warum also diesen Code immer wieder eingeben?

Ein anderes Beispiel ist ICollection. Die überwiegende Mehrheit der Schnittstellenmethoden sind exakt gleich implementiert. Es gibt nur ein paar Methoden, die in Ihrer Klasse einzigartig sind.

Leider ist Mehrfachvererbung sehr leicht zu missbrauchen. Die Leute werden schnell beginnen, dumme Dinge wie die LabelPrinter-Klasse zu tun, die von ihrer TcpIpConnector-Klasse erbt, anstatt sie einfach zu enthalten.

  0

Theoretisch haben Sie Recht, aber in der Praxis ist es sehr schwer, richtig zu werden. Und der Preis (virtuelle Vererbungskonstruktoren) ist ziemlich hoch. 22 feb. 092009-02-22 00:24:35

  0

Dieser Preis wird nur bezahlt, wenn Sie eine gemeinsame geerbte geerbt durch mehrere Vererbungszweige benötigen. In der Praxis passiert dies selten (und wird zu einem Nicht-Problem, wenn die wiederholte Basis keinen Zustand hat). 22 feb. 092009-02-22 00:30:44

+1

"Die Leute werden schnell dumme Sachen wie die LabelPrinter-Klasse von ihrer TcpIpConnector-Klasse erben, statt sie einfach zu enthalten." "Ja wirklich?" Ich habe das oft gehört, aber es ist nie ein Beweis dafür eingetreten. All das Material, das ich je gelesen habe, macht einen ziemlich klaren Unterschied zwischen Komposition und Vererbung, und ich sehe nicht, wie jemand die beiden verwirren könnte. 22 jan. 132013-01-22 10:56:39


1

Es ist wahr, dass die Zusammensetzung einer Schnittstelle (ähnlich wie Java oder C#) plus die Weiterleitung an einen Helfer viele der häufigen Verwendungen von Mehrfachvererbung (insbesondere Mixins) emulieren kann. Dies geschieht jedoch auf Kosten dieses Weiterleitungscodes, der wiederholt wird (und DRY verletzt).

MI öffnet eine Reihe von schwierigen Bereichen, und in letzter Zeit haben einige Sprachdesigner Entscheidungen getroffen, dass die potenziellen Fallstricke von MI die Vorteile überwiegen.

Ähnlich kann man gegen Generika argumentieren (heterogene Container funktionieren, Schleifen können durch (Schwanz-) Rekursion ersetzt werden) und fast jedes andere Merkmal von Programmiersprachen. Nur weil es möglich ist, ohne eine Funktion zu arbeiten, bedeutet das nicht, dass diese Funktion wertlos ist oder nicht dazu beitragen kann, Lösungen effektiv auszudrücken.

Eine große Vielfalt an Sprachen und Sprachfamilien erleichtert es uns als Entwickler, gute Tools auszuwählen, die das vorliegende Geschäftsproblem lösen. Mein Werkzeugkasten enthält viele Gegenstände, die ich selten benutze, aber bei diesen Gelegenheiten möchte ich nicht alles als Nagel behandeln.

+1

Wenn ein Sprachfeature möglicherweise sehr nützlich ist, aber normalerweise schwer missbraucht wird, ist es wahrscheinlich in C++ vorhanden und in Java nicht vorhanden. Unterschiedliche Sprachdesign-Philosophien. 23 feb. 092009-02-23 20:58:24

+1

Ja. Java ist für Idioten gedacht. 22 jan. 132013-01-22 10:58:54


1

Ein Beispiel für die Verwendung von Mixinklassen in unserem Produkt ist das Speichern und Wiederherstellen von Konfigurationen. Es gibt eine abstrakte Mixin-Klasse, die eine Reihe rein virtueller Methoden definiert. Jede Klasse, die gespeichert werden kann, erbt von der Mix-In-Klasse "Sichern/Wiederherstellen", die ihnen automatisch die entsprechende Funktion zum Speichern/Wiederherstellen gibt.

Dieses Beispiel veranschaulicht nicht wirklich die Nützlichkeit der Mehrfachvererbung. Was hier definiert ist, ist ein INTERFACE. Mehrfache Vererbung ermöglicht es Ihnen, auch Verhalten zu erben. Was ist der Sinn von Mixins?

Ein Beispiel; aus Gründen der Rückwärtskompatibilität muss ich eigene Serialisierungsmethoden implementieren.

So erhält jedes Objekt eine Read und Store-Methode wie folgt.

Public Sub Store(ByVal File As IBinaryWriter) 
Public Sub Read(ByVal File As IBinaryReader) 

Ich möchte auch Objekt zuweisen und klonen können. Das würde mir auf jedem Objekt gefallen.

Public Sub Assign(ByVal tObject As <Class_Name>) 
Public Function Clone() As <Class_Name> 

Jetzt in VB6 Ich habe diesen Code immer und immer wieder wiederholt.

Beachten Sie, dass Statemanager ein Stream ist, der Bytearrays liest und speichert.

Dieser Code wird Dutzende Male wiederholt.

Jetzt in .NET bin ich in der Lage, dies zu umgehen, indem Sie eine Kombination aus Generika und Vererbung verwenden. Mein Objekt unter der .NET-Version erhält Assign, Clone und State, wenn sie von MyAppBaseObject erben. Aber ich mag nicht die Tatsache, dass jedes Objekt von MyAppBaseObject erbt.

Ich bin eher Mix nur in der Schnittstelle Clone zuweisen und VERHALTEN. Besser noch mischen Sie separat die Read und Store-Schnittstelle und dann in Assign und Clone mischen. Es wäre sauberer Code meiner Meinung nach.

Aber die Zeiten, in denen ich das Verhalten wiederverwenden, sind von der Zeit, die ich benutze Interface ZWERGE. Dies liegt daran, dass das Ziel der meisten Objekthierarchien NICHT darin besteht, das Verhalten wiederzuverwenden, sondern die Beziehung zwischen verschiedenen Objekten genau zu definieren. Welche Schnittstellen sind dafür ausgelegt? Obwohl es schön wäre, dass C# (oder VB.NET) dazu in der Lage war, ist es meiner Meinung nach kein Show-Stopper.

Der ganze Grund, dass dies sogar ein Problem ist, dass C++ den Ball zuerst fummelte, wenn es um die Schnittstelle vs Vererbung ging. Als OOP debütierte, dachte jeder, dass die Wiederverwendung von Verhaltensweisen die Priorität sei. Aber dies erwies sich als eine Chimäre und nur für bestimmte Umstände nützlich, wie zum Beispiel als UI-Framework.

Später wurde die Idee der Mixins (und anderer verwandter Konzepte in der aspektorientierten Programmierung) entwickelt. Die Mehrfachvererbung wurde als nützlich beim Erstellen von Mix-Ins gefunden. Aber C# wurde entwickelt, kurz bevor dies allgemein anerkannt wurde. Wahrscheinlich wird dafür eine alternative Syntax entwickelt.


1

Ich vermute, dass in C++, MI ist am besten als Teil eines Frameworks (die Mix-in-Klassen zuvor diskutiert). Das einzige, was ich sicher weiß, ist, dass ich jedes Mal, wenn ich versucht habe, es in meinen Apps zu verwenden, die Wahl bereut habe und sie oft herausreiße und durch generierten Code ersetze.

MI ist ein mehr von denen 'verwenden Sie es, wenn Sie es wirklich brauchen, aber stellen Sie sicher, dass Sie es wirklich' Werkzeuge brauchen.


0

Ich hatte es heute zu benutzen, eigentlich ...

war hier meine Situation - ich hatte ein Domänenmodell im Speicher dargestellt, wobei ein A enthielt kein oder mehr Bs (in einem Array dargestellt), die jeweils B Null oder mehr Cs und Cs bis Ds. Ich konnte die Tatsache nicht ändern, dass sie Arrays waren (die Quelle für diese Arrays stammte aus automatisch generiertem Code aus dem Build-Prozess). Jede Instanz musste verfolgen, zu welchem ​​Index im übergeordneten Array sie gehörten. Außerdem mussten sie die Instanz ihrer Eltern verfolgen (zu viele Details, warum). Ich so etwas wie diese geschrieben (es mehr war, und dies ist nicht syntaktisch korrekt, es ist nur ein Beispiel):

class Parent 
{ 
    add(Child c) 
    { 
     children.add(c); 
     c.index = children.Count-1; 
     c.parent = this; 
    } 
    Collection<Child> children 
} 

class Child 
{ 
    Parent p; 
    int index; 
} 

Dann wird für den Domain-Typen, ich habe dies:

class A : Parent 
class B : Parent, Child 
class C : Parent, Child 
class D : Child 

Die eigentliche Implementierung erfolgte in C# mit Schnittstellen und Generics, und ich konnte die Mehrfachvererbung nicht so durchführen, wie ich es hätte, wenn die Sprache dies unterstützte (ein Kopiervorgang musste durchgeführt werden). Also, ich dachte, ich würde SO suchen, um zu sehen, was Leute von Mehrfachvererbung denken, und ich habe Ihre Frage;)

Ich konnte nicht Ihre Lösung der .anotherClass, wegen der Implementierung von add für Parent (verweist darauf - und ich wollte, dass dies keine andere Klasse ist.

Es wurde schlimmer, weil der generierte Code A-Unterklasse etwas anderes hatte, das weder ein Elternteil noch ein Kind war ... mehr Kopie einfügen.

+1

Es scheint, dass Sie das komplexer als nötig machen. Warum haben Sie nicht einfach einen "Node", der einen Elternteil (der NULL sein kann) und mehrere Kinder (die leer sein können) hat. Dann machen Sie einfach A, B, C und D vom Knoten erben. 30 apr. 092009-04-30 01:06:28

  0

Ich wollte in der Lage sein zu sagen, dass Sie nicht die Eltern eines A verweisen oder zu einem Kind D hinzufügen können (weil A keine Eltern hat und D keine Kinder hat). Mit meiner Implementierung wird es nicht kompiliert, wenn Sie es versuchen. Ich habe das auch mit Generics verbessert, so dass du kein C zu einem A, C oder D hinzufügen kannst, oder wenn du auf das Elternteil von B referenzierst, musst du es nicht in ein A umwandeln (es wird ein A sein bereits durch Generika) usw. 15 mai. 092009-05-15 00:56:06