440 likes | 539 Vues
Einführung in die Programmierung Prof. Dr. Bertrand Meyer. Lektion 14: Mehrfachvererbung. Abstraktionen kombinieren. Gegeben sind die Klassen TRAIN_CAR , RESTAURANT Wie würden Sie eine Klasse DINER implementieren?. Beispiele von Mehrfachvererbungen. Separate Abstraktionen kombinieren:
E N D
Einführung in die ProgrammierungProf. Dr. Bertrand Meyer Lektion 14: Mehrfachvererbung
Abstraktionen kombinieren • Gegeben sind die Klassen • TRAIN_CAR, RESTAURANT • Wie würden Sie eine Klasse DINER implementieren?
Beispiele von Mehrfachvererbungen • Separate Abstraktionen kombinieren: • Restaurant, Eisenbahnwagen • Taschenrechner, Uhr • Flugzeug, Vermögenswert • Zuhause, Fahrzeug • Tram, Bus
Warnung • Vergessen Sie alles, was Sie gehört haben! • Mehrfachvererbung ist nicht das Werk des Teufels • Mehrfachvererbung schadet ihren Zähnen nicht • (Auch wenn Microsoft Word sie scheinbar nicht mag: • )
Dies ist wiederholte Vererbung, nicht Mehrfachvererbung A A C B D D Nichtderallgemeine Fall (Obwohleshäufigvorkommt; warum?)
Noch eine Warnung • Dieser Teil der Vorlesung orientiert sich an Eiffel • Java und C# Mechanismen (Einfachvererbung von Klassen, Mehrfachvererbung von Schnittstellen) werden aber auch behandelt • C++ hat unterstützt ebenfalls Mehrfachvererbung, aber ich werde nicht versuchen, diese zu beschreiben.
Mehrfachvererbung: Zusammengesetzte Figuren EinfacheFiguren EinezusammengesetzteFigur
Den Begriff der zusammengesetzten Figur definieren center display hide rotate move … LIST [FIGURE] FIGURE count put remove … COMPOSITE_FIGURE
In der allgemeinen Struktur LIST [FIGURE] FIGURE OPEN_FIGURE CLOSED_FIGURE perimeter* SEGMENT POLYLINE POLYGON ELLIPSE perimeter+ perimeter+ diagonal COMPOSITE_FIGURE RECTANGLE CIRCLE perimeter++ perimeter++ TRIANGLE SQUARE perimeter++
Eine zusammengesetzte Figur als Liste after item forth Cursor
Zusammengesetzte Figuren • classCOMPOSITE_FIGUREinherit • FIGURE • LIST[FIGURE] • feature • display • -- Jede einzelne Figur der Reihenfolge • -- nach anzeigen.dofromstartuntilafterloop • item.display • forthendend • ... Ähnlich für move, rotate etc. ... • end BenötigtdynamischesBinden
Eine Abstraktionsebene höher gehen • Eine einfachere Form der Prozeduren display, move etc. kann durch den Gebrauch von Iteratoren erreicht werden. • Benutzen Sie dafür Agenten. • Wir werden diese in ein paar Wochen behandeln (aber Sie dürfen das Kapitel gerne schon im Voraus lesen).
Mehrfachvererbung: Abstraktionen kombinieren +, –, *, / … <, <=, >, >=, … NUMERIC COMPARABLE (kommutativer Ring) (totaleOrdnungs-beziehung) INTEGER REAL COMPLEX STRING
Die Lösung von Java und C# • Keine Mehrfachvererbung für Klassen • “Schnittstellen”: Nur Spezifikationen (keine Verträge) • Ähnlich wie komplett aufgeschobene Klassen (ohne wirksame Features) • Eine Klasse kann: • Von höchstens einer Klasse erben • Von beliebig vielen Schnittstellen erben
Mehrfachvererbung: Abstraktionen kombinieren +, –, *, / … <, <=, >, >=, … NUMERIC COMPARABLE (kommutativer Ring) (totaleOrdnungs-beziehung) INTEGER REAL COMPLEX STRING
Wie schreiben wir die Klasse COMPARABLE? • deferredclassCOMPARABLE [G]feature less alias"<" (x: COMPARABLE [G]): BOOLEAN deferred end less_equal alias"<=" (x: COMPARABLE [G]): BOOLEAN do Result:= (Current < xor (Current = x)) end greater alias">" (x: COMPARABLE [G]): BOOLEAN doResult:= (x< Current) end greater_equal alias">=" (x : COMPARABLE [G ]): BOOLEAN doResult:= (x<= Current) end end
Die Moral dieses Beispiels • Typisches Beispiel für ein lückenhaftes Programm. • Wir brauchen das volle Spektrum von vollständig abstrakten (aufgeschobenen) Klasse bis zu komplett implementierten Klassen. • Mehrfachvererbung hilft uns, Abstraktionen zu kombinieren.
Ein typisches Beispiel aus der Eiffel-Bibliothek • classARRAYED_LIST[G] inherit • LIST [G] • ARRAY [G] • feature • … ImplementiereLIST-Features mitARRAY- Features … • end For example: i_th(i: INTEGER): G -- Element mitIndex`i’. do Result:= item (i) end Feature von ARRAY
Man könnte auch Delegation benutzen… • class ARRAYED_LIST[G] inherit LIST [G] feature • rep:ARRAY [G] • … ImplementiereLIST–Features mitARRAY- Features, auf repangewendet… end For example: i_th(i: INTEGER): G -- Element mit Index `i’. do Result:= rep item (i) end
Nicht-konforme Vererbung • class • ARRAYED_LIST[G] • inherit • LIST [G] • ARRAY [G] • feature • … ImplementiereLIST-Features mitARRAY- Features … • end ARRAY LIST inherit{NONE} ARRAYED_LIST Nicht-konformeVererbung
B A f C ? Mehrfachvererbung: Namenskonflikte f
B A f renamefasA_f C A_f, f Namenskonflikte auflösen f
B A f f renamefasA_f C A_f, f Konsequenzen des Umbenennens • a1: A • b1: B • c1: C • ... • c1.f • c1.A_f • a1.f • b1.f • Ungültig: • a1.A_f • b1.A_f
Sind alle Namenskonflikte schlecht? • Ein Namenskonflikt muss beseitigt werden, es sei denn, er geschieht: • Durch wiederholte Vererbung (d.h. kein wirklicher Konflikt) • Zwischen Features, von denen höchstens eines wirksam ist.(d.h. die übrigen sind aufgeschoben)
Noch eine Anwendung von Umbenennungen Eine (lokal) bessere Terminologie ermöglichen. Beispiel: child (TREE); subwindow (WINDOW)
Umbenennungen, um die Terminologie zu verbessern • ‘‘Graphische’’ Features:height, width, change_height, change_width, xpos, ypos, move... • ‘‘Hierarchische’’ Features:superwindow, subwindows, change_subwindow, add_subwindow... classWINDOW inherit RECTANGLE TREE[WINDOW] rename parentassuperwindow, childrenassubwindows, add_childasadd_subwindow … end feature ...end ABER: SieheStilregelnbetreffendeinheitlichenFeaturenamen
Features verschmelzen f + A B C f* f* D *aufgeschoben +wirksam
g h f f Features verschmelzen: Mit verschiedenen Namen class D inherit Arename gasf end B Crename hasf end feature ... end h + g* A B C f* D *aufgeschoben +wirksam Umbenennung
Features verschmelzen: wirksame Features f + f + A B C f + f -- f -- D *aufgeschoben +wirksam -- undefiniert
Undefinition deferredclass T inherit S undefinevend feature ... end
Verschmelzen durch Undefinition f + f + f + A B C class D inherit Aundefinef end B undefinefend C feature ... end f-- f-- D *aufgeschoben +wirksam -- undefiniert
Verschmelzen von Features mit unterschiedlichen Namen h g f f f + C h + g + B A class D inherit A undefinefend B rename gasf undefinef end C rename hasf end feature ... end f -- f -- D
Akzeptable Namenskonflikte Wenn geerbte Features alle den gleichen Namen haben, besteht kein schädlicher Namenskonflikt, falls: Sie alle eine kompatible Signatur haben Maximal eines von ihnen wirksam ist Die Semantik eines solchen Falls: Alle Features zu einem verschmelzen Falls es ein wirksames Feature gibt, wird dessen Implementierung übernommen
Verschmelzung von Features: wirksame Features • a1: Ab1: Bc1: Cd1: D • a1.gb1.fc1.hd1.f g+ A f+ B h+ C gf h f D f- f-
Ein Spezialfall der Mehrfachvererbung • Ermöglicht einer Klasse, zwei oder mehrere Vorfahren zu haben. • Beispiel: ASSISTANT erbt vonTEACHERundSTUDENT. UNIVERSITY_MEMBER id TEACHER STUDENT ?? ?? ASSISTANT ???? Dies istein Fall derwiederholtenVererbung.
Indirekt und direkt wiederholte Vererbung A A C B D D
Mehrfachvererbung ist auch wiederholte Vererbung • Ein typischer Fall: copy is_equal ANY copy++ is_equal++ C LIST copyC_copy D is_equalC_is_equal ??
Akzeptable Namenskonflikte Wenn geerbte Features alle den gleichen Namen haben, besteht kein schädlicher Namenskonflikt, falls: Sie alle eine kompatible Signatur haben Maximal eines von ihnen wirksam ist Die Semantik eines solchen Falls: Alle Features zu einem verschmelzen Falls es ein wirksames Feature gibt, wird dessen Implementierung übernommen
Teilen und Abgleichung • Features, wie z.B. f, die auf ihren Vererbungspfaden nicht umbenannt wurden, werden geteilt (shared). • Features, wie z.B. g, die unter unterschiedlichem Namen geerbt werden, werden vervielfältigt (replicated). f g A gg_c gg_b C B D
Wann ist ein Namenskonflikt akzeptabel? • (Konflikt zwischen n direkten oder geerbten Features derselben Klasse. Alle Features haben denselben Namen) • Sie müssen alle kompatible Signaturen haben. • Falls mehr als eines wirksam ist, müssen diese alle vom gleichen Vorfahren (durch wiederholte Vererbung) abstammen.
Der Bedarf nach „select“ Eine mögliche Doppeldeutigkeit entsteht durch Polymorphie und dynamisches Binden: a1: ANY d1: D … a1 := d1a1.copy (…) copy • is_equal ANY C LIST copy ++ • is_equal ++ copyC_copy is_equalC_is_equal D
Die Doppeldeutigkeit auflösen class D inheritLIST [T ] select copy, is_equal end CrenamecopyasC_copy, is_equalasC_is_equal, ...end
Was wir gesehen haben • Einige Spielchen, die man mit Vererbung spielen kann: • Mehrfachvererbung • Verschmelzen von Features • Wiederholte Vererbung