Ich will Klassen schreiben, nur verstehe ich kaum was davon. Ich hab mir einige Bücher, Tutorials und sonstige Onlinekurse durchgelesen, aber sie beantworten nicht alle meine Fragen. Es wird mir zu viel als gegeben angenommen oder wichtige Punkte mit einem Satz abgehandelt. Bei vielen Sachen will ich aber genauer wissen wieso es so funktioniert oder noch wichtiger, wieso es trotzdem funktioniert, obwohl ich es eigentlich anders machen sollte. Die ganzen Tutorials und Kurse werden anscheinend von Leuten geschrieben die die Materie beherrschen und sich deshalb bestimmte Fragen nicht mehr stellen. Deshalb behandeln sie sie auch nicht oder nicht so genau. So muß man bei Kursen einiges einfach akzeptieren ohne zumindest am Anfang zu verstehen wieso es so ist. Deshalb würde ich gerne hier einen Ergänzungskurs anfangen bei dem ich die Fragen stelle die für einen Anfänger interessant sind. Mir ist klar, daß es die Regel gibt pro Thread nur eine Frage zu stellen, aber ich hoffe man macht hier eine Ausnahme, so daß das ganze Thema zusammen bleiben kann. Also verschiedene Fragen aber zum Thema Klasse.
Ich hab viele Fragen, also fange ich mal an und nicht alles auf einmal.
Eine Klasse muß nicht kompliziert sein. Sie kann auch so aussehen:
Delphi-Quellcode:
TYPE
TTest1 = class
a: Byte;
end;
Das ist eine einfache Klasse und ich kann sie sofort nutzen ohne sie weiter auszubauen.
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
Test1: TTest1;
begin
Test1 := TTest1.Create;
Test1.a := 200;
ShowMessage(IntToStr(Test1.a));
Test1.Free;
end;
Da bei Klassen geerbt wird, hat meine Klasse auch einiges von seinem Vorfahr geerbt, darunter auch die Methoden Create und Free. Da ich keine Klasse als Vorfahr genannt habe, wird TObject automatisch angenommen. Somit erbt meine Klasse alle Methoden von TObject. Baue ich auf einem anderen Vorfahrtyp, muß ich den angeben.
Machen wir es jetzt komplizierter und geben a einen Anfangswert.
Delphi-Quellcode:
TYPE
TTest1 = class(TObject)
a: Byte;
constructor Create;
end;
constructor TTest1.Create;
begin
a := 1;
end;
Immer noch eine einfache Klasse, aber hier bekommt a in Create einen Anfangswert. Das Ganze funktioniert übrigens ohne inherited. Liest man sich aber Bücher und Tutorials durch, so steht an erster Stelle, egal wie einfach eine Klasse ist und ob die sich von TObject ableitet, in Create immer inherited. Bei mir nicht. Hab ich jetzt ein Sakrileg begangen? Ich stelle an dieser Stelle mal die Prinzipfrage ob inherited immer nötig ist. Laut etlicher Bücher und Kurse ja, denn das macht man nun mal so. Genauer wird an dieser Stelle selten eingegangen. Create, wie übrigens auch Destroy, von TObject ist nebenbei gesagt leer und ohne Inhalt. Wozu also hier Create mit inherited aufrufen? Wie man merkt möchte ich hier etwas über inherited diskutieren, da überall nur steht, daß es genommen werden soll, ohne genauer drauf einzugehen.
inherited ist dazu da um den Vorfahr aufzurufen. Baue ich auf einer Klasse auf und will nicht nur den Namen erben, sondern auch die Eigenschaften die sich im Vorfahr hinter der Funktion verbergen, dann muß ich den Vorfahr mit inherited aufrufen.
Wie ich allerdings in vielen Beispielen sehen konnte wird inherited genommen ohne groß zu überlegen. Einen Fehler macht man anscheinend nicht wenn man inherited in eine Klasse einbaut die direkt von TObject abstammt, aber wozu nehmen wenn nicht nötig. Das gleiche gilt wohl auch für Destroy. Eine andere Frage ist wozu inherited bei Create immer vorne und bei Destroy immer hinten genommen wird? Rufe ich bei Create mit inherited den Vorfahr der Klasse auf, ist die Sache klar. Zumindest wenn ich etwas nutze was mir der Vorfahr liefert. Nutze ich nichts vom Vorfahr am Anfang, sondern ergänze den nur, ist es doch egal wo inherited steht.
Beispiele wie es nicht üblich ist:
Delphi-Quellcode:
constructor TTest2.Create;
begin
StringList := TStringList.Create;
inherited;
end;
Das gleiche gilt wohl auch beim Destroy.
Delphi-Quellcode:
constructor TTest2.Destroy;
begin
inherited;
StringList.Free;
end;
Ich zähle das Ganze nur wegen dem Verständnis auf. Man kann inherited in jedes Create schreiben, muß es aber nicht wenn es nicht notwendig ist. Wenn man es aber nicht weiß ob es notwendig ist, dann ist es nicht falsch es einzusetzen. Schaden tut es nicht. Bei der Reihenfolge muß inherited bei Create auch nicht immer an erster Stelle stehen, wenn es nicht notwendig ist. Wenn man es aber nicht weiß ob es notwendig ist, dann ist es nicht falsch Create an erster Stelle zu setzen. Schaden tut auch das in der Regel nicht. Hab ich das richtig verstanden?
Ansonsten ist mir nicht ganz klar wieso Delphi das nicht automatisch erledigt. Warum ruft der constructor nicht automatisch den Vorfahr auf? Oder gibt es Situationen wo man den Vorfahr mit Absicht nicht aufruft? Oder ist das mit der Reihenfolge so wichtig, daß man es den Programmierer überläßt. Oder hat das mit constructor und destructor selbst nichts zu tun, denn bei jeder Methode und Eigenschaft muß aufs Neue überlegt werden ob und wo man inherited einsetzt?
Dann folgt bei mir die Frage woher ich wissen soll wo ich inherited wann einsetzten soll? Bei Create und Destroy ist das mehr oder weniger bekannt und deshalb geregelt. Wie aber ist das bei anderen Eigenschaften und Methoden? Wie sieht es bei Assign aus? Woher soll ich wissen wo es hingehört? Bei TStrings.Assign ist inherited hinten, bei TStringList.Destroy ist es sogar mitten drin. Bedeutet das letztendlich, daß wenn ich eine Klasse schreibe ich mich erst mit dem Vorfahr auseinendersetzen muß? Wie gesagt, destroy von TStringList ist mitten drin.
Das waren meine ersten Verständnisfragen. Kann man also abschließend sagen, daß wenn man Klassen schreibt man sich immer erst mit der Vorgängerklasse auseinandersetzen muß? Und lediglich bei einfachen Klassen die auf TObject aufbauen man sich die Arbeit sparen kann, da in der Regel dann nur Create und Destroy angepaßt werden und bei denen macht es keinen Unterschied ob man inherited nimmt oder nicht oder vorne oder hinten?