Klasse ohne inherited?

Für Fragen rund um die Ide und zum Debugger
Antworten
MitjaStachowiak
Lazarusforum e. V.
Beiträge: 395
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Klasse ohne inherited?

Beitrag von MitjaStachowiak »

Hallo,
also dass man den inherited-Befehl braucht, wenn man seine Klasse von einer Parent-Klasse ableitet/deklariert/wie auch immer, ist ja klar. Aber wie sieht es aus, wenn man eine komplett eigene Klasse erstellt, die folglich direkt von TObject kommt?

Code: Alles auswählen

type
 TMyClass = class
  public
   constructor Create;
 end;
 
[...]
 
constructor TMyClass.Create;
begin
 inherited Create;  // hier notwendig?
end;
Ich habe mal gelesen, dass das der Compiler in diesem Fall automatisch machen würde. Wie sieht das mit Lazarus aus?

Ich habe gerade so ein Paar alte Code-Zeilen von mir durchgelesen und da war so eine selbsgemachte Klasse drinn', wo ich auch gleich destructor Free; ohne inherited in die public-Declaration gepackt habe. Najaa, es geht, aber jetzt frage ich mich: Wieso?
Wenn ich das richtig verstanden habe, gibt der destructor am Ende den Speicher der Klasse frei und danach darf nichts mehr in dieser Klasse ausgeführt werden - free dagegen ist nur eine gewöhnliche procedure, die dann destroy am Ende aufruft. Aber was ist der Sinn davon, destroy und free zu trennen?

Benutzeravatar
theo
Beiträge: 10859
Registriert: Mo 11. Sep 2006, 19:01

Re: Klasse ohne inherited?

Beitrag von theo »

A: Wenn's nicht abschmiert, dann ist es nicht notwendig, aber in jedem Fall erlaubt. ;-)
B: Free prüft zusätzlich ob self<>nil ist.

Zu letzterem hab ich mal einen Test gemacht.
Wenn du cn.Destroy aufrufst, schmiert er gleich nochmal ab, mit cn.Free nicht.

Code: Alles auswählen

TAClass = class
  public
    constructor Create;
  end;   
 
...
 
constructor TAClass.Create;
begin
  raise Exception.Create('test');
end;   
 
...
 
procedure TForm1.Button1Click(Sender: TObject);
var
  cn: TAClass;
begin
  try
    try
      cn := TAClass.Create;
    except
    end;
  finally
    //cn.Destroy;
    cn.Free;
  end;
end;

MitjaStachowiak
Lazarusforum e. V.
Beiträge: 395
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Re: Klasse ohne inherited?

Beitrag von MitjaStachowiak »

Vielen Dank, für deine Antwort.
Es ist schon mal gut zu wissen, dass ein fehlendes inherited keinen Datenmüll im Speicher, oder so, verursacht...

Also wenn man den destructor selbst deklariert, müsste kein Fehler kommen, wenn man destroy (oder wie man es eben genannt hat) direkt aufruft.

Code: Alles auswählen

TAClass = class
  public
    constructor Create;
    destructor Destroy;
  end;   
 
...
 
constructor TAClass.Create;
begin
  raise Exception.Create('test');
end;
 
destructor TAClass.Destroy;
begin
end;
Damit wäre dann aber die TObject-Klasse fast völlig außer Funktion gesetzt... Ist das schlimm?

Benutzeravatar
theo
Beiträge: 10859
Registriert: Mo 11. Sep 2006, 19:01

Re: Klasse ohne inherited?

Beitrag von theo »

Nee, bei Destroy musst du override machen, sonst motzt auch der Compiler.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Klasse ohne inherited?

Beitrag von mse »

theo hat geschrieben:

Code: Alles auswählen

 
procedure TForm1.Button1Click(Sender: TObject);
var
  cn: TAClass;
begin
 cn:= nil; //<<<<<<<-----
  try
    try
      cn := TAClass.Create;
       //cn ist im falle einer exception in TAClass.Create undefiniert,
       //TAClass.Destroy wird automatisch aufgerufen, damit in TACLass.Create bereits bezogene
       //resourcen freigegeben werden können. Das heisst, Destroy() muss auf nicht vollständig
       //abgearbeitetes Create() gefasst sein. Darum auch die Nullsetzung des
       //gesamten Objektspeichers vor dem Aufruf von Create().
       //Nach Destroy() wird die exception durch fpc_ReRaise() nochmals gefeuert.
    except
    end;
  finally
    //cn.Destroy;
    cn.Free;   //<<<<<<<------ nicht notwendig im Falle der 
               //    "garantierten exception" in TACLass.Create
  end;
end;

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Klasse ohne inherited?

Beitrag von mschnell »

AFAIK:

"inherited Create"
"inherited" ist nötig, "Create" nicht (außer wenn die Parameter von Create beim Parent anders sind)

"Destructor Free"
Free ist nicht der Destructor, sondern "Destroy", was im endeffekt von free aufgerufen wird.

Destroy braucht aich ein inherided (am Ende, statt am Anfang ).

"Free" braucht man i.A. gar nicht zu deklarieren.

-Michael

MitjaStachowiak
Lazarusforum e. V.
Beiträge: 395
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Re: Klasse ohne inherited?

Beitrag von MitjaStachowiak »

Also ich habe mal dieses Zitat rausgesucht: "Wenn man die Deklaration des Konstruktors und Destruktors weglässt, werden automatisch die der Elternklasse aufgerufen. Dass die beiden Methoden von TObject leer sind, hat AFAIK den Sinn, Fehlermeldungen zu vermeiden, wenn in abgeleiteten Klassen inherited aufgerufen wird. Und wenn Du Free nicht verstehst, dann gib doch mal zum Testen dasselbe Objekt 2 mal direkt nacheinander frei ;)" (http://forum.delphi-treff.de/archive/in ... 30213.html" onclick="window.open(this.href);return false;).
Wenn ich das richtig verstanden habe, steht in TObjekt.Create gar nichts drinn', und inherited hat in nicht abgeleiteten Klassen keine Wirkung :shock: Wie gesagt dachte ich, dass man inherited deswegen weglassen kann. Nur wenn man den Destructor nicht overrided, sondern diesen direkt aufruft, läut man Gefahr, eine bereits freigegebene Klasse noch mal freizugeben --> Fehler!!. Ich habe für diesen Fall aber immer meine eigenen Sicherheitsabfragen gemacht. Naja, gut zu wissen, dass das auch einfacher geht.

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Klasse ohne inherited?

Beitrag von mschnell »

Klar werden die Funktionen der Eltern vererbt, wenn man sie in einer Klasse nicht definiert. Das gilt für Constructor und Destructor genau wie für alle anderen Prozeduren.

Wenn man Constructor und Destructor aber neu definiert, muss man die Funktionen der Vorgänger-Klasse aufrufen. Dazu braucht man das Keyword "inherited", sonst meint man ja die selbst definierte Funktion. "inherited" geht aber auch mit allen anderen Funktionen, nicht nur mit Contructor und Destructor.

Wenn man nur "inherited" ohne einen Aufruf dahinter schreibt, heißt das: "rufe die Funktion des Vorgängers auf, die genauso heißt und zwar mit genau den Parametern, die beim Funktionsaufruf übergeben worden sind".

-Michael

MitjaStachowiak
Lazarusforum e. V.
Beiträge: 395
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Re: Klasse ohne inherited?

Beitrag von MitjaStachowiak »

Genau.

Ich frage mich nur, ob in TObject.Create und TObject.Destroy wirklich wichtiger Code steht, ohne den die Anwendung nicht läuft... Weil ich erinnere mich nicht, in besagtem, alten Programm jemals Fehler deswegen gehabt zu haben.
Na wie auch immer - ich habe jetzt mit Suchen und Ersetzen überall das Inherited eingefügt und destructor Free; wieder in destructor Destroy; umbenannt (mit override)...

schnullerbacke
Beiträge: 1187
Registriert: Mi 13. Dez 2006, 10:58
OS, Lazarus, FPC: Winux (L 1.2.xy FPC 2.6.z)
CPU-Target: AMD A4-6400 APU
Wohnort: Hamburg

Re: Klasse ohne inherited?

Beitrag von schnullerbacke »

MitjaStachowiak hat geschrieben:Genau.

Ich frage mich nur, ob in TObject.Create und TObject.Destroy wirklich wichtiger Code steht, ohne den die Anwendung nicht läuft... Weil ich erinnere mich nicht, in besagtem, alten Programm jemals Fehler deswegen gehabt zu haben.
Na ja,
im Zweifel tauchen die Fehler auf, wenn dem Kombjuder irgendwann die "Puste"(der Speicher) ausgeht oder wenn man versucht mit Destroy etwas frei zu geben, das vor her nicht mit inherited angelegt worden ist.
Faustregel:
Alle Variablen(Daten) die zum Objekt gehören werden in Create angelegt und in Destroy wieder frei gegeben. Dafür werden aber Zeiger auf dem Heap gerichtet die dann eventuell später in der Luft hängen.

Inherited hat aber auch noch den Vorteil, dass man in abgeleiteten Objekten weniger Arbeit hat, man benutzt was schon vorhanden ist und macht nur die neuen Variablen noch bekannt oder beseitigt sie wieder. Beim Auflösen kommt es nämlich eventuell auch auf die richtige Reihenfolge an.

Ist doch elegant, oder nicht? :P
Humor ist der Knopf, der verhindert, daß uns der Kragen platzt.

(Ringelnatz)

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Klasse ohne inherited?

Beitrag von mschnell »

MitjaStachowiak hat geschrieben:Ich frage mich nur, ob in TObject.Create und TObject.Destroy wirklich wichtiger Code steht,
Und ob. In TObject.Create wird der Memory-Block für die Klassenvariablen etc (virual Message Table) angelegt. Destroy ist vermutlich nötig um die Dstruktoren-Kette mit dem "Free" Einsprung zu verbinden.

-Michaelo

Antworten