May 14, 2007

Ist Mehrfachvererbung sinnvoll?

Heute in der Schule ist die Diskussion entstanden ob es ein Anwendungsbeispiel für Mehrfachvererbung gibt, welches nicht einfacher durch Einfachvererbung zu lösen ist. Deshalb meine Frage: Ist Mehrfachvererbung sinnvoll? Wer hat eine Antwort und ein Anwendungsbeispiel?

de.wikipedia.org/wiki/Vererbung_(Programmierung)#Mehrfachvererbung
en.wikipedia.org/wiki/Inheritance_(computer_science)
cs.sfu.ca/CC/354/zaiane/material/notes/Chapter8/node7.html
There is debate as to whether multiple inheritance can be implemented simply and without ambiguity. It is often criticized for increased complexity and ambiguity, as well as versioning and maintenance problems it can cause (often summarized as the diamond problem).Detractors also point out multiple inheritance implementation problems such as not being able to explicitly inherit from multiple classes and the order of inheritance changing class semantics. There are languages that address all technical issues of multiple inheritance, but the main debate remains whether implementing and using multiple inheritance is easier than using single inheritance and software design patterns.
Mir bekannte Anwendungen:
  • Wohnzimmer
    • erbt von Zimmer (Fenster, Boden, Tür usw)
    • erbt von Fernseher
    • erbt von Möbelladen
  • Amphibienfahrzeug
    • erbt von Landfahrzeug
    • erbt von Wasserfahrzeug
  • Chat-Fenster
    • erbt von Fenster
    • erbt von Textfeld
Siehe auch Corsin´s Post.

7 comments:

leo said...

Hallo, ich komme mal von Corsin rüber. Da mein Deutsch immer noch ein bischen besser ist als das Englisch schreibe ich mal hier rein.

Es gibt durchaus Momente in denen Mehrfachvererbung notwendig ist oder zu besseren Lösungen führt. Die Mehrfachvererbung führt aber häufig zu Verwirrung da das Verhalten des Codes nicht immer klar ist (ohne das man die Language-Spec aufgeschlagen hat), auserdem wird sie häufig falsch angewendet.

Als Beispiel behaupte ich nun einfach mal das zwei deiner drei Beispiele falsch sind. Das Wohnzimmer ist wahrlich eine Spezialsierung eines Zimmer, aber kaum von einem Fernsehen oder einem Möbelladen. Oder hast du auf deiner Wohnung schon mal ein Film gesehn oder sie per Fernbedienung gesteuert. (Ich gebe zu beides ist nicht unmöglich, aber eher unwarscheinlich und eine Ableitung von Fernseher würde hier kaum helfen). Eine Wohnzimmer sieht zwar ein wenig ähnlich aus wie ein Möbelladen, vermutlich hast du aber wenig freude wenn deine Wohnung von fremden besucht wird und Leute bei dir Möbel kaufen wollen. Ableiten von einem Möbelladen wird dein Wohlbefinden also auch nicht steigern ;-)

Das Chatfenster könnte man eventuell so implementieren, in der Praxis besteht aber ein Chatfenster wohl aus mehr als einem Textfeld. Deshalb wird ein Chatfenster das Textfeld einfach hinzufügen und dazu noch viele andere Elemente.

Das Amphibienfahrzeug ist hingegen ein super Beispiel. Wenn man hier keine Mehrfachvererbung hat muss man ein wenig tricksen. In Java würde man zum Beispiel von Auto ableiten und dann das hoffentlich vorhandene Interface Schwimmend implementieren (evtl. greift man dabei auf eine interne Instanz von Schiff zu).

Mit der Mehrfachvererbung kommen aber neue Probleme. Wenn beide Klasse die Methode "bewegen" implementieren, welche wird dann aufgerufen? Was passiert wenn "schwimmen" aufgerufen wird während das Amphibienfahrzeug an Land steht? Und viele andere Fälle. Solche Fragen lassen sich dann meist nur mit der Sprachreferenz lösen (wenn es überhaupt eine solche gibt) und die ist meist recht trocken geschrieben.

Solche Überlegungsfehler passieren vielen Programmierern und führen zu grässlichem Code, ich bin desshalb grundsätzlich gegen Mehrfachvererbung.

Selbstverständlich gibt es (selten) auch praktische Fälle (neben dem Amphibienfahrzeug). Ich bin bisher aber erst einmal auf ein Problem gestossen in dem mir Mehrfachvererbung wirklich gefehlt hat. Es hat sich dabei um zwei Spezialsierungen eines Visitor gehandelt die ich gerne beide gleichzeitig verwendet hätte. Die einzige Möglichkeit dies ohne ganz wüste Hacks zu machen ist Mehrfachvererbung (die ich aber in Java in diesem Fall leider nicht hatte).

Um es nochmal kurz zu fassen es kann durchaus einen "need" für Mehrfachvererbung geben, meist wird Mehrfachvererbung jedoch falsch eingesetzt.

Tim said...

Ich sehe das genauso wie Leo. Die klassische Umsetzung eines Wohnzimmers oder eines Chatfensters ist viel mehr das Decoratormuster. Mit dessen Hilfe wird ein Objekt mit verschiedenen Objekten einer oder mehrerer Standard-Schnittstellen bestückt oder dekoriert. Dabei werden Objekteigene Methoden an ein anderes, zugewiesenes Objekt weiter delegiert.

Es hat den Vorteil, wenn einem die Funktionsweise eines Dekorationsobjektes (bspw. der Fernseher) gegen ein neues Objekt mit der gleichen Schnittstelle ausgetauscht werden kann. Und das zur Runtime!

Aufgrund der von Leo beschriebenen Probleme bin ich ebenfalls kein Fan von Mehrfachvererbung. Zu groß sind die Missverständnisse und zu klein der Benefit.

Stefan2904 said...

Wohnzimmer und Chatfenster waren Corsin´s Idee. ;)

leo said...

Jaja immer die anderen.

Aber wenn der Corsin schon alles wüsste müsste er ja nicht mehr studieren und er würde 3 Jahre auf dem schönsten Campus der Schweiz verpassen ;-)

Mecki78 said...

Also, auch ich stimme Leo völlig zu. Nur eines der beiden Beispiele ist sinnig. Aber genau bei dem ergeben sich grosse Probleme. Wenn alle Fortbewegungsmittel eine Metode haben, die sagt, wie sie sich fohrtbewegen, z.B. Fussgänger sagt "Ich gehe" und Radl sagt "Ich fahre", Flugzeug sagt "Ich fliege" und Auto sagt auch "Ich fahre" und Schiff sagt "Ich schwimme" und U-Boot sagt "Ich tauche"... was sagt dann ein Fahrzeug das von Auto und Schiff erbt? Ich meine, es kann die Methode überschreiben, also keine von den geerbten nehmen und sagen "Ich fahre oder ich schwimme" und dann passt es wieder.

Aber gerade bei Vererbung geht es doch darum, dass man eben "erbt" (legt der Name ja nahe). Wenn ich aber beim Erben immer nur in Probleme renne, wo ich die geerbten Methoden überschreiben muss, weil sie sonst keinen Sinn mehr ergeben, dann muss ich sie gar nicht erben, ich muss ja eh alles neu scheiben. In dem Fall würde das ein Protokoll lösen. Ein Protokoll (so nennt das Objective-C, in Java ein Interface) sagt nur aus, welche Methoden eine Klasse hat, aber es liefert keine Implementierung mit.

Zurück zum Fortbewegungsmittel. Ich würde Fortbewegungsmittel als Protokoll spezf. und Auto und Boot usw. sind tatsächlich auch Protkolle, die aber erben. Dann kann eine Klasse beliebig viele Protkolle implementieren, so gibt es auch Fahrräder mit Motor, so was zwischen Fahrrad und Motorrad. Um hier nicht immer alles neuschreiben zu müssen kann man trotzdem Klassen einführen, mit echter implementierung. So kann PKW durchaus von der selben Klasse erben wie LKW. Und deren Parent Klasse implementiert eben Auto. Ist nur eine Frage, wie man die nennen soll. Vielleicht AbstraktesAuto. Die Klasse an sich muss dann als Abstrakt definiert sein, auch wenn sie alle Methoden implementiert hat von Auto, aber sie stellt ja kein spezielles Auto da, sondern mehr den Typ Auto an sich.

Tatsächlich bin ich noch nie in einen Fall gelaufen, wo Mehrfachveerbung wirklich sinnig wäre. Ich versuche mir die ganze Zeit welche Auszudenken, aber so wirklich gute gibt es nicht. Oft wird es missbraucht, damit ein Objekt z.B. sowohl ein Collection Typ als auch was ganz anderes ist, was gar nichts damit zu tun hat. Aber dann ist eigentlich Kapselung richtig. Z.B. beim Chatfenster. Ein Chatfenster ist ein Fenster, das stimmt. Aber es ist kein Textfeld. Es *HAT* ein Textfeld, das ist grosser Unterschied. Und klar ist es schön, wenn ich es dirket in Methoden werfen kann, die ein Textfeld erwarten. Stattdessen kann ich aber genauso myChatFenster.getTextfield() in die Methoden schmeissen und alles wird gut :)

Es gibt da schon ein Beispiel, was ich mir ausdenken kann:

Getraenk hat die Unterklassen Limonade, Saft, Wasser

Suessungsart hat die Unterklassen Zuckergesuesst, Suessstoffgesuesst, Fruchtzuckergesuesst, Ungesuesst

Cola ist eine Limonade und ist Zuckergesuesst. Cola Light ist auch eine Limonade aber Suessstoffgesuesst. Orangensaft ist ein Saft und Fruchtzuckergesuesst.

Nun kann ich sagen, Getraenk ist eine echte Klassenveerbung und Suessungsart sind Interfaces. Klar, geht super! Nur wenn eben Suessungsart Methoden hat, dann muss ich die bei JEDEM Getränk diese implementieren. Ansonsten, wenn ich mit Abstrakten Klassen arbeiten möchte, dann muss ich für jede Kombination aus jeder Getraenke Klasse und jedem Interface eine Abstrakte Klasse machen, wie z.B. LimonadeMitZucker und von der würde dann Cola erben. Aber das macht unglaublich viele Klassen.

Stefan2904 said...

Auf die Frage "Ist Mehrfachvererbung sinnvoll?": Ja oder nein?

(-;

Anonymous said...

class Nein : private Mehrfachvererbung, public IstAbsoluter, protected Bloedsinn {
...
}

Post a Comment

Bitte bei anonymen Kommentaren
einen Namen angeben!