![]() |
Delphi-Version: XE2
Vererbung und Polymorphie
Hallo zusammen.
Ich habe ein Verständnisproblem und wollte hier mal um Ratschlag bitten, dazu erläutere ich am besten erstmal mein Problem. Es gibt eine Oberklasse TMensch. Von ihr sind zwei Unterklassen abgeleitet, TJob und TSchule. Diese Klassen haben nochmals Unterklassen. TJob ist die Oberklasse zu TArbeiter, TSportler und TAzubi. TSchüler ist die Unterklasse von TSchule. Das ist mein Aufbau. Ich habe nun eine einzige Liste Menschlist. Über eine RadioGroup wähle ich aus, wen ich hinzufügen möchte. Ich fülle ein Formular und gebe diese Eintragungen an eine Variable des Typen TMensch. Hier ist das 1. Problem, denn TMensch kennt nicht die Variablen von seinen Unterklassen. Damit das aber der Fall ist, brauche ich eine Function, die mir doch quasi die Variablen übergibt, sodass es funktioniert oder? Damit Polymorphie aber seine Wirkung hat, muss diese Function wiederverwertbar sein, eventuell durch dynamischen Binden. 2. Problem: Gehen wir einen Schritt weiter und sagen, ich kann die Liste befüllen. Dann hat Arbeiter z.B. 8 Werte und Schüler 10. Damit habe ich doch eine Differenz von 2. Wie wirkt sich das auf die Liste aus und vor allem auf meine Ausgabe. Wird die Liste dann mit nichts befüllt? 3. Problem: Ich wähle über die Radiogroup einen Typen aus, zum Beispiel Arbeiter. Dann möchte ich aber auch nur Arbeiter angezeigt bekommen. Wie sage ich das der Liste? Brauche ich Fixpunkte, die mir sagen, welcher Listeneintrag wer ist? Ich weiß, dass sind viele Probleme auf einmal, aber ich hoffe dennoch, dass ihr mir ein wenig Denkanstoß geben könnt. Gruß Jan |
AW: Vererbung und Polymorphie
Moin,
willkommen in der Welt der OOP. Und das meine ich ernst und nicht sarkastisch, da die OOP wohl eines der wichtigsten Werkzeuge ist. Dennoch hast Du noch einen gewissen Weg vor Dir, Deine Klassenhierarchie macht auf den ersten Blick wenig Sinn. Und ja, eine Oberklasse kennt die Felder nicht, die erst in Unterklassen eingeführt werden. Das muss so sein. Aus meiner Sicht macht es wenig Sinn, jetzt an Deiner Hierarchie herumzudoktern, ich denke, Du solltest kurz ein OOP-Tutorial überfliegen. Im Idealfall mit Delphi, aber letztlich ist es egal, da die darin enthaltenen Informationen unabhängig von der Programmiersprache sein werden. Wirf doch mal einen Blick in den Delphi Crash Kurs: ![]() |
AW: Vererbung und Polymorphie
Hallo Daniel,
der Link war neu für mich und nur bedingt hilfreich, da nur der theoretische Teil gegen Ende neue Informationen gegeben hat. Der Rest war mir nämlich bekannt. Mir ist der Sinn von OOP deutlich, die Klassenhierarchie kommt auch nicht von mir, sondern ist mir vorgegeben worden. Genauso soll die Get-Function in der Klasse TMensch bestehen. Also suche ich nach einem Ansatz, wie ich das lösen kann, sodass die Aufgabenstellung erfüllt wird. Gruß Jan |
AW: Vererbung und Polymorphie
Zum 1. Problem gäbe es die Möglichkeit, dass die jeweilig abgeleitete Klasse das Eingabeformular für seine Daten selbst bereitstellt. Du musst nur eine virtuelle Methode von TMensch aufrufen, damit sich das Objekt selbst abfragt.
2. Problem: Weitere virtuelle Funktion, die z.B. eine übergebene Stringliste füllt oder ein TStringDynArray zurückgibt. 3. Problem: Es gibt eine Funktion, die einem den Klassennamen zurückgibt. Mit "is" kommt man ebenfalls zum Ziel. |
AW: Vererbung und Polymorphie
Hallo Mikkey,
ich habe eine Unit Neu die das Eingabeformular stellt. Dieses Formular wird aufgerufen, wenn ich in meiner Mainform einen Button klicke. Ich trage die Daten ein und habe vier verschieden Set-Functions die mir eine Variabel vom Typen TMensch beschreiben. Anschließend habe ich eine Get-Function die mir Arbeiter resultet. Die anderen zwei Möglichkeiten probiere ich, sobald ich das erste Problem beseitigt habe. Gruß Jan |
AW: Vererbung und Polymorphie
Hallo,
Zu Problem 1: Im Button-Click fragst du die Radio-Group ab. Je nachdem erstellst du eine Instanz der gewünschten Klasse und fügst diese zu deiner Menschenliste hinzu. In diesem Schritt musst du natürlich explizit auf die Felder der abgeleiteten Klassen zugreifen. Zu Problem 2: Es ist doch egal wie viele Werte die einzelnen Objekte in der Menschenliste haben. Da in der Liste ja nicht die kompletten Objekte sondern jeweils nur Pointer (4 bzw. 8 Byte groß) auf die Objekte gespeichert werden hat das überhaupt keine Auswirkung auf die Liste selbst. Edit: Oder was wahrscheinlich noch besser wäre wäre eine Funktion in der Art wie Mikkey es vorgeschlagen hat, die dafür sorgt dass über eine virtuelle Methode das Objekt selbst dafür sorgt wie es z.B. ausgegeben wird (wäre vor allem für Problem 3 sehr praktisch) Zu Problem 3: In diesem Fall würdest du die Menschenliste mit einer Schleife durchlaufen und nur die Objekte in irgendeiner Weise darstellen/anzeigen die von der Klasse TArbeiter abgeleitet sind:
Delphi-Quellcode:
Generelles:
for i:= 0 to Menschenliste.Count-1 do
begin if Menschenliste[i] is TArbeiter then DisplayMensch(Menschenliste[i]); end; // oder besser: for i:= 0 to Menschenliste.Count-1 do begin if Menschenliste[i] is TArbeiter then Menschenliste[i].Display(AnzeigePanel); // o.ä. end; Wenn du auf Objekte in der Liste zugreifst kannst du erstmal nur auf die Felder zugreifen die in TMensch deklariert wurden. Möchtest du Felder abgeleiteter Klassen lesen/schreiben musst du vorher prüfen von welcher Klasse das Objekt abgeleitet ist (s.o.) und danach das Objekt casten.
Delphi-Quellcode:
Ich bin mir aber auch generell nicht ganz sicher was du mit deinen Fragen meinst. Aber ich glaube du denkst z.T. falsch bzw. zu kompliziert.
var arbeiter: TArbeiter;
begin if Menschenliste[0] is TArbeiter then begin arbeiter := TArbeiter(Menschenliste[0]); arbeiter.Stundenlohn := 15.0; end; end; |
AW: Vererbung und Polymorphie
Wenn man der Oberklasse eine Handvoll (ggf. abstrakter) Methoden spendiert, könnte man sich außer bei der Filterung doch die ganzen "is"-Abfragen sparen.
Delphi-Quellcode:
Wenn man nun eine Liste von TOberdings hat, kann man die Methoden SetValues und DisplayValues für jedes einzelne Element aufrufen, ohne sich um dessen konkreten Unterklassentyp scheren zu müssen. Weiterhin wäre auch der Ansatz über Interfaces denkbar, das ist dann noch einen Tacken abstrakter, da man noch nicht einmal eine bestimmte Klassenhierarchie einhalten müsste.
type
TOberdings = class public procedure SetValues; virtual; abstract; procedure DisplayValues; virtual; abstract; end; TErstesUnterdings = class(TOberdings) public procedure SetValues; override; procedure DisplayValues; override; end; TZweitesUnterdings = class(TOberdings) public procedure SetValues; override; procedure DisplayValues; override; end; |
AW: Vererbung und Polymorphie
Ich will auch mal zur Verwirrung beitragen...
Wenn Du Menschen in eine Liste speicherst steht dort drin nur -> Zeiger auf Objekt -> Zeiger auf Objekt -> Zeiger auf Objekt -> Zeiger auf Objekt Du kannst Dir dann auch nur Objekte dort heraus holen. Wenn Du dort nur Menschen gespeicherst hast kannst Du einfach die Objekte in Menschen casten ->
Delphi-Quellcode:
Falls der erste Mensch tatsächlich ein Schüler war kannst Du an die Schülereigenschaften nicht heran.
Mensch := TMensch(List[0]);
Wenn der erste Eintrag ein Auto war, dann knallt es (bestenfalls sofort oder mit unvorhersehbaren Folgen später), da u.U. Speicherplätze beschrieben werden, die gar nicht zu dem eigentlichen Objekt gehören. Wenn Du Menschen, Schüler und Arbeiter in der Liste hast musst Du prüfen, was Du gerade vorliegen hast:
Delphi-Quellcode:
O := List[0];
if (O is TSchueler) then Schueler := (O as TSchueler) else if (O is TArbeiter) then Arbeiter := (O as TArbeiter) else if (O is TMensch) then Mensch := (O as TMensch); Generische Listen akzeptieren nur bestimmte Objekte und geben die entsprechend wieder zurück. Bei einer generischen Menschenliste würdest Du also immer einen TMensch zurück erhalten. Solche Listen sind u.a. nützlich, wenn man eine bestimmte Klasse speichern und sich das ständige Casten ersparen will. Ein kurzer Ausflug, weil Du "Polymorphie" geschrieben hast: Letztlich kannst Du Dich auch mal zu Schnittstellen (Interfaces) einlesen. Da kann man völlig unterschiedliche Objekte speichern und weiter verarbeiten, die aber einheitliche Eigenschaften haben. Z.B. hätte ein Auto und ein Motorrad jeweils eine Schnittstelle IVerbrennungsmotor. Der Verbrennungsmotor kann dann gestartet werden (Verbrennungsmotor.Start), ohne dass der Zündschlüssel wissen muss, ob am Motor ein Auto hängt oder ein Motorrad. Dadurch kann man Klassen voneinander entkoppeln und flexibel mit ihnen umgehen. |
AW: Vererbung und Polymorphie
Mahlzeit :),
danke für die Antworten. Die Lösung für mein erstes Problem, was DeddyH geschrieben hat, wende ich jetzt auch an, nur habe ich kleine Schwierigkeiten. Ich habe das ganze mal an einem Beispiel ausprobiert.
Delphi-Quellcode:
Ich habe versucht das ganze anhand eines Schachspieles zu probieren, bevor ich mir mein eigentliches Programm ganz zerlege.
unit Schach;
interface uses system.generics.collections, Dialogs, system.sysutils; type TSchachfigur = class Reichweite: integer; procedure setreichweite(); function InString(): string; virtual; end; type TSchachBauer = class(TSchachfigur) Form: string; procedure setform(); function InString(): string; override; end; type TSchachSpringer = class(TSchachfigur) Position: integer; procedure setposition(); function InString(): string; override; end; type Tschachspiel = class fschachfiguren: Tobjectlist<TSchachfigur>; constructor create; end; implementation function TSchachbauer.InString: string; begin result := Form; end; procedure TSchachBauer.setform; begin Form := 'kantig'; end; constructor Tschachspiel.create; var I: integer; temp: TSchachfigur; begin fschachfiguren := Tobjectlist<TSchachfigur>.create; temp := TSchachBauer.create; fschachfiguren.add(temp); temp := TSchachSpringer.create; fschachfiguren.add(temp); for I := 0 to fschachfiguren.Count - 1 do begin showmessage(fschachfiguren[I].InString); end; end; function TSchachSpringer.InString: string; begin result := IntToStr(Position); end; procedure TSchachSpringer.setposition; begin Position := 1; end; function TSchachfigur.InString: string; begin result := IntToStr(Reichweite); end; procedure TSchachfigur.setreichweite; begin Reichweite := 7; end; end. Aber ich bekomme in der Messagebox einmal nichts und dann einmal "0". Woran liegt das? So wie das Programm aufgebaut ist, ist auch mein eigentliches Programm. Gruß Jan Edit: Ich konnte das Problem gerade eben selber lösen, indem ich nicht den Umweg über die Set-Procedure gemacht habe. Aber wie geht das mit dieser? UND bei der Ausgabe wird nicht der Wert von Schachfigur ausgegeben. Wie bekomme ich es hin, dass dieser dann auch ausgegeben wird? |
AW: Vererbung und Polymorphie
Ich würde vorschlagen, du verlegst die Adds und Castings weitegehend in die Liste, dann tust du dir anschließend leichter. Mit Generics geht das wahrscheinlich noch einfacher (keine Ahnung, hab D2007).
Delphi-Quellcode:
procedure TMenschTestForm.SomeButtonClick(Sender: TObject);
var Menschen: TMenschen; Index: integer; begin Menschen := TMenschen.Create; try Index := Menschen.AddSportler; Menschen.Sportler[Index].SomeProp := 'Fußball'; ShowMessage(IntToStr(Menschen.SportlerCount)); finally Menschen.Free; end; end;
Delphi-Quellcode:
TMenschen = class(TObjectList)
private function GetArbeiter(Index: integer): TArbeiter; function GetAzubi(Index: integer): TAzubi; function GetJob(Index: integer): TJob; function GetMensch(Index: integer): TMensch; function GetSchueler(Index: integer): TSchueler; function GetSchule(Index: integer): TSchule; function GetSportler(Index: integer): TSportler; function GetArbeiterCount: integer; function GetAzubiCount: integer; function GetJobCount: integer; function GetMenschCount: integer; function GetSchuelerCount: integer; function GetSchuleCount: integer; function GetSportlerCount: integer; function GetIsArbeiter(Index: integer): boolean; function GetIsAzubi(Index: integer): boolean; function GetIsJob(Index: integer): boolean; function GetIsMensch(Index: integer): boolean; function GetIsSchueler(Index: integer): boolean; function GetIsSchule(Index: integer): boolean; function GetIsSportler(Index: integer): boolean; public function AddMensch: integer; function AddJob: integer; function AddSchule: integer; function AddArbeiter: integer; function AddSportler: integer; function AddAzubi: integer; function AddSchueler: integer; property MenschCount: integer read GetMenschCount; property JobCount: integer read GetJobCount; property SchuleCount: integer read GetSchuleCount; property ArbeiterCount: integer read GetArbeiterCount; property SportlerCount: integer read GetSportlerCount; property AzubiCount: integer read GetAzubiCount; property SchuelerCount: integer read GetSchuelerCount; property Mensch[Index: integer]: TMensch read GetMensch; property Job[Index: integer]: TJob read GetJob; property Schule[Index: integer]: TSchule read GetSchule; property Arbeiter[Index: integer]: TArbeiter read GetArbeiter; property Sportler[Index: integer]: TSportler read GetSportler; property Azubi[Index: integer]: TAzubi read GetAzubi; property Schueler[Index: integer]: TSchueler read GetSchueler; property IsMensch[Index: integer]: boolean read GetIsMensch; property IsJob[Index: integer]: boolean read GetIsJob; property IsSchule[Index: integer]: boolean read GetIsSchule; property IsArbeiter[Index: integer]: boolean read GetIsArbeiter; property IsSportler[Index: integer]: boolean read GetIsSportler; property IsAzubi[Index: integer]: boolean read GetIsAzubi; property IsSchueler[Index: integer]: boolean read GetIsSchueler; end; implementation { TMenschen } function TMenschen.AddArbeiter: integer; begin Result := Add(TArbeiter.Create); end; function TMenschen.AddAzubi: integer; begin Result := Add(TAzubi.Create); end; function TMenschen.AddJob: integer; begin Result := Add(TJob.Create); end; function TMenschen.AddMensch: integer; begin Result := Add(TMensch.Create); end; function TMenschen.AddSchule: integer; begin Result := Add(TSchule.Create); end; function TMenschen.AddSchueler: integer; begin Result := Add(TSchueler.Create); end; function TMenschen.AddSportler: integer; begin Result := Add(TSportler.Create); end; function TMenschen.GetArbeiter(Index: integer): TArbeiter; begin if IsArbeiter[Index] then Result := TArbeiter(Items[Index]) else raise Exception.Create('GetArbeiter'); end; function TMenschen.GetAzubi(Index: integer): TAzubi; begin if IsAzubi[Index] then Result := TAzubi(Items[Index]) else raise Exception.Create('GetAzubi'); end; function TMenschen.GetSchueler(Index: integer): TSchueler; begin if IsSchueler[Index] then Result := TSchueler(Items[Index]) else raise Exception.Create('GetSchueler'); end; function TMenschen.GetJob(Index: integer): TJob; begin if IsJob[Index] then Result := TJob(Items[Index]) else raise Exception.Create('GetJob'); end; function TMenschen.GetMensch(Index: integer): TMensch; begin if IsMensch[Index] then Result := TMensch(Items[Index]) else raise Exception.Create('GetMensch'); end; function TMenschen.GetSchule(Index: integer): TSchule; begin if IsSchule[Index] then Result := TSchule(Items[Index]) else raise Exception.Create('GetSchule'); end; function TMenschen.GetSportler(Index: integer): TSportler; begin if IsSportler[Index] then Result := TSportler(Items[Index]) else raise Exception.Create('GetSportler'); end; function TMenschen.GetArbeiterCount: integer; var I: integer; begin Result := 0; for I := 0 to Count - 1 do if IsArbeiter[I] then Inc(Result); end; function TMenschen.GetAzubiCount: integer; var I: integer; begin Result := 0; for I := 0 to Count - 1 do if IsAzubi[I] then Inc(Result); end; function TMenschen.GetJobCount: integer; var I: integer; begin Result := 0; for I := 0 to Count - 1 do if IsJob[I] then Inc(Result); end; function TMenschen.GetMenschCount: integer; var I: integer; begin Result := 0; for I := 0 to Count - 1 do if IsMensch[I] then Inc(Result); end; function TMenschen.GetSchuleCount: integer; var I: integer; begin Result := 0; for I := 0 to Count - 1 do if IsSchule[I] then Inc(Result); end; function TMenschen.GetSchuelerCount: integer; var I: integer; begin Result := 0; for I := 0 to Count - 1 do if IsSchueler[I] then Inc(Result); end; function TMenschen.GetSportlerCount: integer; var I: integer; begin Result := 0; for I := 0 to Count - 1 do if IsSportler[I] then Inc(Result); end; function TMenschen.GetIsArbeiter(Index: integer): boolean; begin Result := Items[Index] is TArbeiter; end; function TMenschen.GetIsAzubi(Index: integer): boolean; begin Result := Items[Index] is TAzubi; end; function TMenschen.GetIsJob(Index: integer): boolean; begin Result := Items[Index] is TJob; end; function TMenschen.GetIsMensch(Index: integer): boolean; begin Result := Items[Index] is TMensch; end; function TMenschen.GetIsSchule(Index: integer): boolean; begin Result := Items[Index] is TSchule; end; function TMenschen.GetIsSchueler(Index: integer): boolean; begin Result := Items[Index] is TSchueler; end; function TMenschen.GetIsSportler(Index: integer): boolean; begin Result := Items[Index] is TSportler; end; |
AW: Vererbung und Polymorphie
Zitat:
Du könntest den Figuren jeweile einen eigenen Konstruktor spendieren, der (um im Beispiel zu bleiben) mal die Form, mal die Position setzt. Oder, um mal Polymorphie auszunutzen: Die Basisklasse bekommt eine virtuelle abstakte Prozedur "Initialisieren" oder so. Die Prozedur wird in jeder Klasse anders überschrieben und setzt halt einmal die Form, ein anderes mal die Position, was weiß ich. Dann kannst du folgendes schreiben:
Code:
Und schon haben deine Figuren auch was, das sie beim ToString ausgeben können.
var
I: integer; temp: TSchachfigur; begin fschachfiguren := Tobjectlist<TSchachfigur>.create; temp := TSchachBauer.create; temp.Initialisieren; fschachfiguren.add(temp); [...] ------------------------------------ Du solltest aber besser auf dein ursprüngliches Problem zurückkommen: Was brauchst du wirklich für Klassen und wofür. Dann kann man vllt. besser helfen. Worin sollen sich die einzelnen Menschen unterscheiden? |
AW: Vererbung und Polymorphie
Hallo Jumpy,
ich komme auf deinen Ratschlag mal zurück. Ich habe eine Klasse TMensch:
Delphi-Quellcode:
Dann eine Klasse TJob:
FHerkunft: string;
FName: string; FGeburtsdatum: Tdate; FGroeße: extended; FGeschlecht: boolean; FFamilienstand: string;
Delphi-Quellcode:
Dann eine Klasse TSchule:
FGehalt: extended;
FArbeitszeit: integer; FBeruf: string;
Delphi-Quellcode:
Dann eine Klasse TArbeiter:
FSchulfaecher: string;
FNotendurchschnitt: extended; FSchulform: string;
Delphi-Quellcode:
FChef: boolean;
Dann eine Klasse TSportler:
Delphi-Quellcode:
Dann eine Klasse TAzubi:
FSportart: string;
FErrungenschaften: string;
Delphi-Quellcode:
Dann eine Klasse TSchueler:
FNotendurchschnitt: extended;
FSchulfaecher: string; FSchulform: string;
Delphi-Quellcode:
Das sind alle meine Klassen mit den Variablen. Ein einem extra Formular lese ich Editfelder aus und möchte die gerne in eine Variable von TMensch schreiben, was aber nicht geht, da TMensch die Klassenvariablen aber nicht kennt. Ich hoffe das ist jetzt verständlich.
FKlassenfahrt: boolean;
FKlassensprecher: boolean; Gruß Jan |
AW: Vererbung und Polymorphie
Also mir ist nicht klar, was Du genau willst...
Den Inhalt von EditBeruf kannst Du nicht ein ein TMensch-Objekt schreiben. Du musst dafür ein TJob-Objekt (TAngestellter wäre sicher passender) vorliegen haben. Andersrum kannst Du in ein TJob-Objekt auch alles schreiben, was in TMensch deklariert ist. Oder geht es Dir eher darum, wie Du die Eingabeformulare organisieren sollst? |
AW: Vererbung und Polymorphie
Also ich soll mit einer Liste arbeiten, nämlich: Menschlist: TObjectList<TMensch>
Diese möchte ich befüllen, mit den Inhalten, die aus den Editfelder in einem anderen Formular ausgelesen werden. Ich möchte diese ausgefüllten Sachen in eine Variable von TMensch schreiben, was aber nicht geht, da ich ja zum Beispiel nicht "Mensch.FSchulform" abfragen kann, weil TMensch diese Variable nicht kennt. Dies soll nach dem Schema gehen, welches ich versucht habe mit den Schachfiguren zu verdeutlichen, aber ich schaffe es nicht. Sobald das funktioniert, brauche ich eine ToString-Methode die mir die verschiedenen Werte in Strings umwandelt, damit ich das in einem Memofeld ausgeben kann. Das bekomme ich ja mit "override" hin. |
AW: Vererbung und Polymorphie
Wenn wir zunächst bei deiner Vererbungstruktur aus #1 bleiben sind zumindest die Namen TJob und TSchule unglücklich gewählt (als Kinder von TMensch). Besser wäre TMenschMitJob und TMenschInDerSchule.
Schaust du dir den Azubi-Berufsschüler an, beruht der bei dir auf TJob, braucht aber auch eigenschaften als Schüler und bekommt die wieder extra. Das ist doch irgendwie blöd. Mehrfachvererbung gibt es ja (in Delphi) nicht, sonst wäre das vllt. gegangen. Somit ist doch irgendwie der ganze Ansatz schon nicht gut. Mal als Verbesserungsvorschlag. Definiere eine Klasse TJob und TSchulinfo oder so. Als separate Klassen, die nicht von TMensch erben! Stattdessen bekommt TMensch nun variablen für Objekte des Typs TJob und TSchulinfo. Vererbung ist bei der OOP nicht alles (und wird glaub ich immer weniger (wg. Testbarkeit???) genutzt. Stattdessen werden Klassen verknüpft (Aggregation/Assoziation) (wg. Testbarkeit meist über Interfaces). Du kannst dem TMensch ja dann noch Boolean-Funktionen ala "IstSchüler" "HatJob" mitgeben. Jetzt soll Mensch 12 aus der Liste angeschaut/editiert werden:
Code:
//Edit-Felder des Formulars mit Werten aus TMensch verknüpfen oder füllen.
if TMensch(Menschliste[12]).HasJob then begin //Zusätzlich einen Frame (Unterform) laden, mit EditFeldern für Job //Edit-Felder mit Werten versorgen end //Analog für Schulinfo |
AW: Vererbung und Polymorphie
Die Menschen- und Schachfigurenbeispiele passen nicht so richtig zusammen.
Die Schachfiguren sind quasi alle gleich. Sie sehen etwas unterschiedlich aus und gestatten etwas andere Züge. Sie stehen alle auf einem Schachbrett rum und können versetzt oder davon entfernt werden. Insofern müsste man die Figuren nicht unbedingt in unterschiedlichen Klassen abbilden. Bei den Personen sieht es schon anders aus. Sie stehen in unterschiedlichen Kontexten und eigentlich haben Schüler mit Mitarbeitern nichts weiter zu tun - außer dass alles Menschen sind (i.d.R. ;-) ) und über einen Namen und Geburtsdatum verfügen. In einer realen Anwendung würde man vermutlich Schüler und Angestellte in verschiedenen Listen verwalten und jeweils angemessen mit beiden Listen umgehen. Wenn man nun alle Namen und Zusatzinfos auflisten will würde man zunächst AlleAngestelltenToString und dann AlleSchülerToString aufrufen. Wenn Du (warum auch immer) lieber AlleMenschen (durcheinander) in einer Liste verwalten willst, kannst Du auch AlleMenschenToString aufrufen. TMensch.ToString wäre dann in TAngestellter und TSchüler überschrieben. Die Funktion muss dann nicht wissen, ob sie hier einen Angestellten oder Schüler vor sich hat. Wenn Du letzteres willst, dann brauchst Du nur ein FormAngestellter und FormSchüler definieren, bei dessen OK-Button einen TAngestellten oder TSchüler erzeugen (sowie die Edit-Daten in das Objekt schreiben) und das jeweilige Objekt in die Menschenliste werfen. AlleMenschen kannst Du später wie oben beschrieben als String ausgeben. Wenn das das Ziel ist, sollte das kein Problem sein. Für eine reale Anwendung taugt der Ansatz aber nicht wirklich. Ich habe z.B. in meiner Turniersoftware Spieler definiert. Ein Spieler hat einen Status (spielt gerade, wartet, ist bereit, ist verletzt usw). Ein Spieler ist natürlich auch eine Person und die Person ist wiederum Mitglied in einem Verein (oder in mehreren). Ein Spieler kann wiederum in verschiedenen Turnieren spielen und dort unterschiedliche Stati haben. Daher verwalte ich in Spielern und Vereinsmitgliedern lediglich Instanzen auf ein und die selbe Person. Je nach Gegebenheit kann so etwas auch eine sinnvolle Lösung sein. Handelt es sich bei Deiner Aufgabe um eine Übungsaufgabe, die nur die Strings liefern soll oder gibt es da noch einen weiteren Hintergrund? Vielleicht können wir das noch besser einordnen wenn mir noch mehr erfahren... |
AW: Vererbung und Polymorphie
Das ist doch alles vom Ansatz schon total falsch :roll:
Hier wird gerade alles durcheinander geworfen. Wie kann man
Delphi-Quellcode:
von
TJob
Delphi-Quellcode:
ableiten?
TMensch
Selbst
Delphi-Quellcode:
kann man nicht von
TSchueler
Delphi-Quellcode:
ableiten.
TMensch
Denn
Delphi-Quellcode:
ist eine Rolle die ein
TSchueler
Delphi-Quellcode:
einnimmt. Somit wäre das also eine Eigenschaft, die man hat oder nicht oder nicht mehr hat.
TMensch
Somit ist also
Delphi-Quellcode:
ein Aggregat und kann eben Bezug zu diesen Rollen haben mit entsprechenden Eigenschaften.
TMensch
Daraus würde sich dann folgender Ansatz ergeben
Delphi-Quellcode:
Jetzt kann man z.B. alle Menschen herausfiltern, die Schüler der Schule xy sind.
TRolle = class
end; TMensch = class property Rollen[Index:Integer] : TRolle read GetRolle; end; TSchule = class end; TSchulKlasse = class property Schule : TSchule; end; TSchueler = class( TRolle ) property Klasse : TSchulKlasse; end; |
AW: Vererbung und Polymorphie
Zitat:
Das ist doch wie im richtigen Leben. Einen Deutschen sprichst Du deutsch an, einen Engländer englisch. Und einen 'Menschen'? Mit dem kannst Du nur in einer allen Menschen gemeinen Sprache sprechen (Mimik, Musik z.B.) Na ja, hinkt vielleicht ein wenig. |
AW: Vererbung und Polymorphie
Zitat:
Zitat:
|
AW: Vererbung und Polymorphie
Zitat:
Delphi-Quellcode:
//
Menschlist.Add (ErzeugeNeuenMenschen()); // Zitat:
Delphi-Quellcode:
Du erzeugst also konkrete Menschableitungen und setzt deren explizite Eigenschaften.
Function TForm1.ErzeugeNeuenMenschen() : TMensch;
Begin Case WelcherMenschSollErzeugtWerden of Arbeiter : Result := ErzeugeArbeiter(); Schueler : Result := ErzeugeSchueler(); .... End; // Hier noch die allen Menschen gemeinsamen Eigenschaften setzen End; Function TForm.ErzeugeArbeiter() : TArbeiter; Begin Result := TArbeiter.Create; Result.StundenLohn := StrToFloat(EditFeldStundenLohn.Text); Result.IstChef := CheckBoxIstChef.Checked; End; Function TForm.ErzeugeSchueler() : TSchueler; Begin Result := TSchueler.Create; Result.Schulform := .... End; Jeder Schüler und jeder Arbeiter ist auch ein Mensch, aber nicht umgekehrt. Schau Dir genau die Deklaration an. Das passt so. Die Variable 'Result' (das Funktionsergebnis) ist vom Typ 'TMensch'. Ich kann ihr aber einen TArbeiter oder TSchueler zuweisen. In der Funktion 'ErzeugeSchueler' ist das Funktionsergebnis hingegen ein 'TSchueler'. Da du der abstrakten Basisklasse 'TMensch' noch eine virtuelle Methode 'ToString' spendierst, und die dann in allen Kindklassen überschreibst bzw. erweiterst, solltest Du dann damit durch sein. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:01 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