 Ja, herzlich willkommen zurück zu Programmiert bei Radikmen. Wir sind hier im fünften und letzten Teil des Moduls Daten, Abstraktionen und Objekteorientierung und in diesem letzten Teil soll es um verschiedene Formen von Vererbungen gehen, bei denen eben nicht nur von einer Klasse geerbt wird, sondern wir entweder Mix-in-Inheritance verwenden, wir werden gleich sehen, was das ist, oder Multiple-Inheritance, also von mehreren Klassen gleichzeitig erben. Fangen wir erstmal mit ein bisschen Motivation an, also warum will man das vielleicht in einer Programmiersprache haben, dass man eben nicht nur eine Klasse von einer anderen Klasse erben lassen kann, sondern von mehreren Dingen. Also wenn man sich so die große Welt der Dinge mal anschaut, dann ist es oft schwer, einen einzigen Vererbungsbaum aufzubauen, bei dem jede Klasse nur eine einzige Elternklasse hat. Es gibt viele Fälle, wo das einfach natürlicherweise nicht so richtig viel Sinn macht. Also ein einfaches Beispiel wäre, wenn ich zum Beispiel eine Klasse habe, die eine Katze darstellt, dann ist diese Klasse vielleicht, oder diese Katze sowohl ein Tier als auch ein Haustier und wenn ich jetzt schon existierende Klassen Animal und Pet habe, möchte ich vielleicht von beiden Klassen erben, sodass ich von beiden den Code entsprechend wieder verwenden kann. Ein anderes Beispiel ist, wenn ich zum Beispiel ein Widget habe in einer Datenbank-Applikation, dann habe ich vielleicht verschiedene Eigenschaften, die die solche Widgets haben sollen. Zum Beispiel soll das sortierbar sein und ich habe vielleicht schon eine Implementierung von sortierbaren Daten. Ist vielleicht etwas, was ich als Graf darstellen möchte, also was ich plotten möchte und gibt es vielleicht schon existierende Datenabstraktion, namens Graphable, oder gleichzeitig soll es natürlich auch irgendwie speicherbar sein und vielleicht habe ich auch dafür schon existierende Implementierung, die Storyville heißt. Und die Frage ist, wie kann ich all diese Implementierung wieder verwenden, wenn ich eben nur von einer Elternklasse immer oder einer Eltern-Datenabstraktion erben kann. Eine Antwort auf diese Frage ist die sogenannte Mix-in-Inheritance. Also was wir hier haben, ist sowas ähnliches wie diese Klassen Vererbung, die wir bis jetzt die ganze Zeit gesehen haben, plus das eben nicht wirklich die komplette Klasse geerbt wird, sondern dass eine klassenartige Abstraktion Methoden anbietet, die dann anschließend in einer Unterklasse vermischt werden können, also Mix-in werden können, ohne dass man explizit von dieser klassenartigen Abstraktion erbt. Und der Vorteil, wenn man quasi nicht von einer kompletten Klasse erbt, sondern andere Sachen reinmixt und wir werden gleich sehen, was diese anderen Sachen sind, der Name hängt ein bisschen von der Programmiersprache ab, ist, dass man ohne größere simantische Probleme die ja verschiedene Mix-ins in eine Klasse vereinen kann. Also ich kann zum Beispiel Mix-ins namens Animal und Pet haben und die dann beide in meiner Klasse Cat vereinen und somit von beiden Animal und Pet Methoden wieder verwenden. Verschiedene Programmiersprachen bieten dieses Konzept von Mix-ins in verschiedenen Varianten an. Eine Sprache, wo das schon relativ lange drin ist, ist Scala, da gibt es die sogenannten Traits, die im Prinzip genau das sind, was ich gerade beschrieben habe und mithilfe der man bestimmte Methoden anbieten kann, die dann anschließend alle in einer Klasse vereint werden können. In Java gibt es Interfaces, was man als sehr leichtgewichtige Version von Mix-ins auffassen kann. Vor Java 8 waren Interfaces im Prinzip nur Beschreibung der Signatur von Methoden, also keine Implementierung, aber seit Java 8 gibt es auch Default Implementations von Methoden in Interfaces. Das heißt, ich kann da tatsächlich schon Code zur Verfügung stellen, der dann, wenn ich ein Interface implementiere, sozusagen reingemixed wird in meine Klasse. Und als drittes Beispiel, Ruby bietet auch so was in der Art an, und zwar in Form der sogenannten Include-Modules, mit denen ich bestimmte Module in eine Klasse inkludieren kann und damit auch Methoden wiederverwenden kann, ohne explizit eine Vererbungsrelation zu erstellen. Neben Mix-ins gibt es eine andere mögliche Antwort auf diese Frage, wie ich von verschiedenen Dingen erben kann. Und zwar bieten viele Sprachen eine echte Mehrfachvererbung an, was im Prinzip bedeutet, dass ich mehrere Klassen gleichzeitig erweitern kann. Das geht zum Beispiel in C++ oder Python oder auch OCaml. Und hier unten sehen wir mal ein kleines Beispiel aus C++, wo ich vielleicht schon zwei existierende Klassen Person und System User habe. Und wenn ich jetzt ein System schreibe, in dem Studenten verwaltet werden sollen, möchte ich vielleicht einschaften und auch Code von diesen beiden Klassen erben und das Ganze in eine neue Klasse Student vereinen. Und das kann ich in C++ zum Beispiel machen, indem ich wirklich von diesen beiden existierenden Klassen erbe. Und was dann passiert, ist, dass dieser neue Klasse Student alle Felder und alle Methoden dieser Superklasse bekommt und somit ja das Verhalten und auch den Zustand von beiden Klassen erbt. Die Mehrfachvererbung hat einen interessanten Effekt auf die Struktur, in der die Klassen dann entsprechend der Vererbungsrelation schlussendlich angeordnet sind. Also wenn wir einfach nur einfach Vererbung haben, dann bekommen wir eine Klassen Hierarchie, die einem ja die schlussendlich ein Baum ist. Also wir könnten da zum Beispiel irgendwo eine Oberklasse namens A haben. Und die hat dann vielleicht Subklassen B und C und D. Und D könnte nochmal eine Subklasse namens E haben. Und egal, wie viel weitere Klassen und Vererbungsrelation ich jetzt hier einfügt, was ich am Ende rausbekomme, ist immer ein Baum. Also wir haben keine Zyklen und doch keine Kanten, die wieder zu einem zurückgehen zu einer der Knoten oder Klassen, die wir hier schon haben. Anders sieht das aus, wenn wir Mehrfachvererbung haben, denn jetzt haben wir eben keinen Baum mehr. Sondern was wir hier bekommen ist ein gerichteter, erzüglicher Graph oder auf Englisch dann Directed A-Cyclic Graph, zielungsweise kurz auch einfach Deck. So und das sieht dann ein bisschen anders aus. Hier könnte ich zum Beispiel eine Klasse X haben, von der V und W erben, sagen wir mal von W erbt auch noch Z. Und jetzt könnte ich hier unten eine Klasse Y haben, die sowohl von V als auch von Z erbt. Und was daraus kommt, ist offensichtlich kein Baum mehr, sondern eben so ein Deck. Und eine interessante Situation, die sich daraus ergibt, ist das sogenannte Diamond Problem, was im Prinzip bedeutet, dass es mehrere Pfade zu derselben Superklasse geben kann. Also hier in unserem Beispiel hätten wir zum Beispiel mehrere Pfade, die von Y zu X schlussendlich gehen. Und das führt zu interessanten semantischen Problemen, wenn man versucht eine Sprache mit Mehrfachvererbung zu kompilieren, bzw. überhaupt erst mal zu definieren, was dann die Semantik dieser Sprache ist. Hier sind mal einige dieser semantischen Probleme aufgelistet, die unter anderem aus diesem Diamond Problem entstehen. Eines der Probleme ist zum Beispiel, wenn ich zwei Parent-Klases habe, also zwei Klassen, von denen geerbt wird, die beide eine Methode mit demselben Namen anbieten. Welche der Methoden wird dann tatsächlich in meiner Subklasse verwendet, die von der einen Klasse oder die von der anderen Klasse und wie wird entschieden, welche Methode da Priorität hat. Eine andere Frage ist, und das hängt mit dem Diamond Problem zusammen. Wenn ich zwei Elternklassen habe, die jeweils den gleichen, also die gleiche Grandparent-Klasse haben, also selbst ein gemeinsames, eine gemeinsame Elternklasse wieder haben, haben wir dann ein oder zwei Kopien der Felder, die von diesem Grandparent geerbt werden. Wenn wir noch mal zurückgehen hier zu unserem Beispiel von gerade eben, wenn ich jetzt Y anschaue, das erbt ja von X, aber über diese zwei Pfade und X hat jetzt vielleicht ein Feld namens FU, dann ist die Frage, ob Y jetzt zweimal dieses Feld FU hat, nämlich einmal so wie es über V geerbt wird und einmal so wie es über Z und W geerbt wird oder ob es nur eines dieser Felder FU gibt. Das dritte Problem, das wir noch kurz ansprechen, möchte ist, wie diese Objekte dann überhaupt im Speicher repräsentiert werden können und wie man es überhaupt hinbekommen kann, dass man diese schöne Eigenschaft, die wir gerade eben mit den V-Tables gesehen haben, nämlich dass die Unterklassen oder die Instanzen der Unterklassen jeweils ein Prefix von Instanzen der Oberklassen sind. Wie bekommt man das hin und bekommt man das überhaupt hin. All das sind interessante Fragen. Wir schaffen es jetzt hier in der Vorlesung nicht, die wirklich im Detail zu beantworten und die Antwort hängt wie so oft natürlich auch immer von der jeweiligen Programmiersprache ab. Also ich belasse es hier einfach mal damit, die Fragen einfach mal den Raum zu werfen und wer sich da mehr für interessiert, der findet im Buch, was zur Vorlesung gehört, ganz interessante Antworten dazu. So, zum Abschluss dieses fünften Teils und auch das gesamte Moduls, Datenabstraktion und Objektorientierung haben wir noch ein kleines Quiz, und zwar wieder in der Form von vier Sätzen, die ich mir ausgedacht habe, von denen manche stimmen und manche auch nicht und die Frage für Sie ist wieder, welche dieser Sätze stimmen denn jetzt. Bitte einfach das Video hier wieder anhalten, kurz drüber nachdenken, dann den Ilias abstimmen und anschließend erst die Lösung anschauen. Schauen wir uns mal an, was davon stimmt. Also die ersten beiden Sätze stimmen schon mal nicht. Der erst hat gesagt, dass Static und Dynamic Method Binding in einer statisch typisierten Sprache das Gleiche sind, aber wir haben jetzt ja gerade lang und breit gesehen, dass in C++, das zum Beispiel nicht das Gleiche ist, sondern C++ ist statisch typisiert, also stimmt der Satz nicht. Beim zweiten geht es um V-Tables, die speichern nicht die Felder eines Objekts, sondern eben die Methoden eines Objektes. Der dritte Satz stimmt, eine Klasse kann auf mehrere Mixins aufbauen und die sozusagen in sich vereinen und damit die Methoden von verschiedenen Mixins wiederverwenden und der letzte Satz stimmt nicht. In Java kann eine Klasse nur eine andere Klasse direkt erben oder von einer anderen Klasse direkt erben, also wir haben keine Mehrfachvererbung in Java. Ja und dann sind wir auch schon am Ende dieses Moduls zum Thema Datenabstraktion und Objektorientierung. Vielen Dank fürs Zuhören und bis zum nächsten Mal.