![]() |
[OOP]: sinnvolle Vererbung
Schon seit längerer Zeit versuche ich mich in die OOP einzuarbeiten.
Nun hab ich aber oft Probleme mit der Vererbung. Ich kenne die meisten Compilerdirektiven (virtual, override usw.), hab aber trotzdem Probleme. Neuerdings hab ich mir eine Liste zusammengeproggt, und das meiner Klasse TMyList implementiert. Dort brauche ich natürtlich auch eine Wurzel:
Delphi-Quellcode:
Nun hab ich aber eine Weiterentwicklung von TKnoten gemacht, natürlich durch Vererbung.
TMyList = class
private Wurzel: TKnoten; public procedure Hinzufuegen; {...} end; Diese Weiterentwicklung von TKnoten möchte ich nun in eine weitere Listenklasse implementieren.
Delphi-Quellcode:
Ihr sehr jetzt mein Problem mit der Wurzel, und ich habe ja auch Hinzufuegen von TMyList geerbt.
TMyNewList = class(TMyList)
private Wurzel: TNewKnoten; public {...} end; Leider arbeitet die Prozedur Hinzufügen mit TKnoten. Muss ich jetzt die Methode Hinzufügen in TMyNewList neu implentieren, oder kann ich mit inherited auf Hinzufügen zugreifen, allerdings mit Instanzen von TNewKnoten? |
Re: [OOP]: sinnvolle Vererbung
Da TMyList nur TKnoten kennt, musst du der Prozedur eine "runtergecastete" Instanz von TMyKnoten übergeben -->
Delphi-Quellcode:
Wenn du auf irgendwas zugreifen musst, was in TNewKnoten enthalten ist, dann musst du die Proezdur neu implementieren, vielleicht geht es sogar so:
TMyList = class
private Wurzel: TKnoten; public procedure Hinzufuegen(var Neu: TKnoten); {...} end; TMyNewList = class(TMyList) private Wurzel: TNewKnoten; public {...} end; ... //Aufruf var Liste: TMyNewList; NeuerKnoten: TNewKnoten; begin ... NeuerKnoten := TNewKnoten.Create; Liste.Hinzufügen(NeuerKnoten); //von Typ TNewKnoten, der von TKnoten abstammt ...
Delphi-Quellcode:
procedure TMyNewList.Hinzufuegen((var Neu: TNewKnoten);
begin inherited Hinzufuegen; // weiß nicht genau, vielleicht auch so: inherited Hinzufuegen(Neu); //Mach irgendwas mit Neu als TNewKnoten end; |
Re: [OOP]: sinnvolle Vererbung
Muss ich Wurzel: TNewKnoten üverhaupt in TMyNewList neu implementieren, oder kann ich Wurzel von TMyList irgendwie manipulieren?
|
Re: [OOP]: sinnvolle Vererbung
Müsstest Du können. Allerdings hast du Wurzel:TKnoten als private deklariert, deswegen ist das nur in dieser Klasse sichtbar. Damit die Ableitungen (TMyNewList) auf das Wurzel-Attribut aus der Mutterklasse zugreifen kann, musst du es als protected oder public deklarieren:
Delphi-Quellcode:
nun ist Wurzel vom Typ TKnoten auch in den abgeleiteten Klassen sichtbar.
TMyList = class
protected Wurzel: TKnoten; public procedure Hinzufuegen(var Neu: TKnoten); {...} end; |
Re: [OOP]: sinnvolle Vererbung
Zitat:
Zitat:
Delphi-Quellcode:
function TMyNewList.GetWurzel: TNewKnoten;
begin Result := Wurzel; // Eigenschaften kopieren... Result.Irgendwas := TMyList(Self).Wurzel.Irgendwas; // vielleicht geht sogar Result.Irgendwas := inherited Wurzel.Irgendwas oder so ähnlich??? end; |
Re: [OOP]: sinnvolle Vererbung
Zitat:
Was ist der Unterschied zwischen
Delphi-Quellcode:
und
TMyNewList(MyList)
Delphi-Quellcode:
?
MyList as TMyNewList
|
Re: [OOP]: sinnvolle Vererbung
Zitat:
Zitat:
|
Re: [OOP]: sinnvolle Vererbung
Schau Dir dazu doch auch mal in der Unit Classes.pas der VCL (source liegt Deiner Enterprise ja bei) die beiden Klassen TCollection und TCollectionItem an.
Dort ist das so implemetiert, das Du beim erzeugen der (abgeleiteten) Collection/Liste den Typ (also die Klasse) der Items mitgibst. Diese werden dann durch eine Classfactory als entsprechende Objekte hinzugefügrt / created. |
Re: [OOP]: sinnvolle Vererbung
Zitat:
Wobei es mittels Polymorphie auch funktionieren müsste, wenn TNewKnoten von TKnoten abgeleitet wird. Dann müsste er in der TMyNewList ein Objekt von TNewKnoten in dem Wurzel-Attribut von TKnoten instanzieren können. |
Re: [OOP]: sinnvolle Vererbung
@Bowler: Wie bitte? Könntest du das etwas einfacher erklären?
Danke! P.S.: Bitte nicht im Konjunktiv schreiben! :-D |
Re: [OOP]: sinnvolle Vererbung
Zitat:
|
Re: [OOP]: sinnvolle Vererbung
Hm..ok, ich versuchs.
Also, Polymorphie bedeutet, dass Du ein Attribut mit dem Typ Deiner Basis-Klasse anlegst, und dann - wenn Du das Objekt letztendlich mit .Create erzeugst - nichtmehr die Basis-Klasse erstellst, sondern eine davon abgeleitete Klasse. Hier das ganze mal als Code:
Delphi-Quellcode:
Dann die Implementierung:
type
TBasisKlasse = class(TObject) public iErgebnis:integer; procedure Berechne(a,b:integer); end; TAddierenKlasse = class(TBasisKlasse) public procedure Berechne(a,b:integer); override; end; TSubtrahierenKlasse = class(TBasisKlasse) public procedure Berechne(a,b:integer); override; end;
Delphi-Quellcode:
Dadurch hast Du eine Basisklasse, und 2 davon abgeleitete Klassen, mit der gleichen Funktion. Beide funktionen machen etwas unterschiedliches. In der Funktion der Basisklasse steht nichts, da es sich um eine leere Dummy-Funktion handelt.
procedure TBasisKlasse.Berechne(a,b:integer);
begin // Dummy-Funktion end; procedure TAddierenKlasse .Berechne(a,b:integer); begin self.Ergebnis=a+b; end; procedure TSubtrahierenKlasse .Berechne(a,b:integer); begin self.Ergebnis=a-b; end; Im Deinem Programm dann:
Delphi-Quellcode:
Das mal zum Thema Polymorphie (ich hoffe, es ist soweit richtig @all :) ).
var
meinMatheObejkt:TBasisKlasse; function Addieren; begin meinMatheObjekt:=TAddierenKlasse.Create; meinMatheObjekt.Berechne(10,5); ShowMessage(IntToStr(meinMatheObjekt.Ergebnis)); // = 15 FreeAndNil(meinMatheObjekt); end; function Subtrahieren; begin meinMatheObjekt:=TSubtrahierenKlasse.Create; meinMatheObjekt.Berechne(10,5); ShowMessage(IntToStr(meinMatheObjekt.Ergebnis)); // = 5 FreeAndNil(meinMatheObjekt); end; Das würde in Deinem Konkreten Fall bedeuten, dass Du in Deiner TMyNewList-Klasse kein Attribut für einen Knoten einbinden musst, sondern das Attribut aus der Mutterklasse lassen kannst (TKnoten). Wenn Du nun die TKnoten-Klasse erweitern willst, dass z.B. im Kontruktor noch etwas mehr passiert, als in TKnoten, dann leitest Du dir von TKnoten eine neue Klasse ab (TNewKnoten). In den Methoden Deiner TMyNewListe kannst Du dann in Dein Wurzel-Attribut, welches Du aus der Mutterklasse hast und von Typ TKnoten ist, ein Objekt vom Typ TNewKnoten erzeugen. D.h, Du kannst zu Laufzeit entscheiden, welches Objekt letzten Endes in dem Attribut vorhanden ist. Hui, ganz schön viel stoff. Ich hoffe, es hilft dir. :-D Gruß Christian |
Re: [OOP]: sinnvolle Vererbung
Zitat:
P.S.: Ein virtual abstract in der abstrakten Klasse erspart dir das schreiben einer Dummy-Methode! ;-) |
Re: [OOP]: sinnvolle Vererbung
Zitat:
Delphi-Quellcode:
:-D
procedure Berechne(a,b:integer); virtual; abstract;
|
Re: [OOP]: sinnvolle Vererbung
Zitat:
Zitat:
|
Re: [OOP]: sinnvolle Vererbung
Sorry, wusste nicht, dass das Wurzel-Objekt schon erstellt ist.
|
Re: [OOP]: sinnvolle Vererbung
Zitat:
Das Wurzelobjekt wird doch bereits als abgeleitete Klasse erzeugt, damit kann die Mutter demnach auf alle Basismethoden wie gehabt darauf zugreifen. Beispiel:
Delphi-Quellcode:
TListe = class
wurzel: TItem; wurzelklasse: TItemClass; function Hinzufuegen: TItem; constructor Create(itemklasse: TItemClass); end; TItem = class end; TItemClass = Class of TItem; TMyItem = class end; TMyItemClass = class of TMyItem; constructor TListe.Create(itemklasse: TItemClass); begin wurzelklasse := itemklasse; end; function TListe.Hinzufuegen: TItem; begin result := wurzelklasse.Create; end; Nun kann man mit
Delphi-Quellcode:
alle beliebigen abgeleiteten Items direkt durch die Basisliste instanzieren lassen.
var
l_liste: TLIste; l_item: TItem; l_myItem: TMyItem; begin l_liste := TListe.Create(TItemClass); l_item := l_liste.Hinzufuegen; l_liste.Free; l_liste := TLIste.Create(TMyItemClass); l_myItem := l_liste.Hinzufzuegen as TMyItem; end; |
Re: [OOP]: sinnvolle Vererbung
Ja, sicher, ich bin aber davon ausgegangen, dass er von TMyList ableiten möchte ohne dass er dort irgendwas ändert und trotzdem auch das Wurzel-Objekt eine vom alten Wurzel-Objekt abgeleitete Klasse hat!
|
Re: [OOP]: sinnvolle Vererbung
Zitat:
// edit: OK. Ich verzeihe dir :mrgreen: |
Re: [OOP]: sinnvolle Vererbung
Zitat:
|
Re: [OOP]: sinnvolle Vererbung
Vielen Danke für die Posts! :-D
Bedanke mich bei (alphabetisch):
Zitat:
Danke |
Re: [OOP]: sinnvolle Vererbung
Zitat:
Du hast die Klasse TMyList mit Wurzel als TKnoten vorgegeben und kannst oder darfst sie nicht mehr im Design verändern. Du möchtest davon eine Klasse ableiten, die aber Knoten als TNewKnoten implementiert. |
Re: [OOP]: sinnvolle Vererbung
Zitat:
Ich hoffe es sich verständlich. :? |
Re: [OOP]: sinnvolle Vererbung
Ich hab dir mal ein kleines Beispiel zusammengebastelt:
Delphi-Quellcode:
Somit hast du dann eigentlich zwei Objekte (beide jeweils private und somit gekapselt und nur über properties ansprechbar!), wobei das zweite die ererbten Methoden, Eigenschaften von dem gelinkten Objekt verwendet. Sommit kannst du Wurzel in TMyNewList verändern und dann eine aus TMyList ererbte Funktion aufrufen, die irgendwas mit Wurzel macht. Anschließend kannst du die veränderten Werte von Wurzel in TMyNewList wieder abrufen.
{...}
type TKnoten = class FZahl: Integer; public property Zahl: Integer read FZahl write FZahl; end; TMyList = class FWurzel: TKnoten; public constructor Create; destructor Destroy; override; function Verdopple: Integer; property Wurzel: TKnoten read FWurzel write FWurzel; end; // WICHTIG: Jeder Zugriff auf ererbte Eigenschaften muss über das LinkedObject laufen TNewKnoten = class(TKnoten) FText: string; FLinkedObject: TKnoten; private function GetZahl: Integer; procedure SetZahl(const Value: Integer); public constructor Create(LinkedObject: TKnoten = nil); destructor Destroy; override; property Text: string read FText write FText; property Zahl: Integer read GetZahl write SetZahl; end; TMyNewList = class(TMyList) FWurzel: TNewKnoten; public constructor Create; destructor Destroy; override; property Wurzel: TNewKnoten read FWurzel write FWurzel; end; {...} implementation { TMyList } constructor TMyList.Create; begin FWurzel := TKnoten.Create; end; destructor TMyList.Destroy; begin FreeAndNil(FWurzel); inherited; end; function TMyList.Verdopple: Integer; begin Result := FWurzel.Zahl * 2; end; { TNewKnoten } constructor TNewKnoten.Create(LinkedObject: TKnoten = nil); begin FLinkedObject := LinkedObject; end; destructor TNewKnoten.Destroy; begin FLinkedObject := nil; end; function TNewKnoten.GetZahl: Integer; begin if Assigned(FLinkedObject) then Result := FLinkedObject.Zahl else Result := FZahl; end; procedure TNewKnoten.SetZahl(const Value: Integer); begin if Assigned(FLinkedObject) then FLinkedObject.Zahl := Value else FZahl := Value; end; { TMyNewList } constructor TMyNewList.Create; begin inherited; FWurzel := TNewKnoten.Create(TMyList(Self).Wurzel); end; destructor TMyNewList.Destroy; begin FreeAndNil(FWurzel); inherited; end; {...} |
Re: [OOP]: sinnvolle Vererbung
Danke, Stevie! :-D
Phoenix hat mir folgende PN geschickt: Zitat:
|
Re: [OOP]: sinnvolle Vererbung
Klar, wenn man beide Klassen neu erstellt, ist das der beste Weg.
Allerdings geht das eben nicht, wenn man eine schon bestehende Klasse hat, die man erweitern will. |
Re: [OOP]: sinnvolle Vererbung
Ich danke allen Postern, für die vielen Antworten. Danke :-D
In meinem Falls werde ich Klassenreferenztypen (class of) verwenden, aber auch der Vorschlag von Stevie werd ich mir merken. TCollection und TCollectionItem sind ideale Beispiele für Klassenreferenztypen (Phoenix). Hier noch ein alter Thread, bezüglich "class of": ![]() Der Thread ist [erledigt], Danke :-D |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:28 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz