Delphi-PRAXiS
Seite 4 von 4   « Erste     234   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Warum virtuelle Destructoren? (https://www.delphipraxis.net/86842-warum-virtuelle-destructoren.html)

JasonDX 20. Feb 2007 01:33

Re: unsichtbare Klassen
 
So, jetzt nochmal gaaaaaanz laaaaangsam, und schoooooeeen detailliert:
Regeln:
  1. Wird eine Methode als Delphi-Referenz durchsuchenvirtual deklariert, erhaelt sie einen Eintrag in der VMT.
  2. Wird eine Methode als Delphi-Referenz durchsuchenoverride deklariert, wird der vorherige Eintrag der VMT ueberschrieben.
  3. Welche VMT verwendet wird, entscheidet das Instanzieren. Es wird immer auf die VMT verwiesen, dessen Konstruktor aufgerufen wurde.

So, und nun was passiert:
Gegeben sei folgende Klasse
Delphi-Quellcode:
TMeineKlasse = class(TObject)
  constructor Create();
  destructor Destroy(); //override;
end;
und diese 2 Variablen:
Delphi-Quellcode:
var
  meineKlasseObject: TObject;
  meineKlasse: TMeineKlasse;
welche beide mit
Delphi-Quellcode:
TMeineKlasse.Create();
initialisiert werden.
Beobachten wir nun beide moeglichkeiten, und rufen bei beiden Instanzen die Destroy-Methode auf (weil du ja meinst, mit Free waere das ganze gezinkt :roll: )
Zuerst ohne override:
Delphi-Quellcode:
meineKlasse.Destroy();
Der Kompiler guckt: meineKlasse ist als TMeineKlasse deklariert. Davon soll nun die Methode "Destroy" aufgerufen werden. Ja, die is da deklariert, und dementsprechend wird auch TMeineKlasse.Destroy aufgerufen.
nun
Delphi-Quellcode:
meineKlasseObject.Destroy();
Der Kompiler guckt: meineKlasseObject ist als TObject deklariert. Davon soll nun die Methode "Destroy" aufgerufen werden. Ja, TObject.Destroy() gibts, und ist als virtual derklariert. Also guckt er in der VMT nach: Durch das instanzieren mit TMeineKlasse.Create() wird auf die VMT von TMeineKlasse verwiesen. Dort findet sich allerdings immernoch nur der Eintrag auf TObject.Destroy(), also wird TObject.Destroy aufgerufen. -> Speicherleck (siehe mein vorheriger Beitrag).

so, und nun das ganze mit override:
beim aufruf von
Delphi-Quellcode:
meineKlasse.Destroy
veraendert sich nichts. Der Kompiler sieht immernoch die Methode TMeineKlasse.Destroy() (weil meineKlasse als TMeineKlasse deklariert ist), und ruft dementsprechend auch TMeineKlasse.Destroy() auf.
Der Unterschied kommt bei
Delphi-Quellcode:
meineKlasseObject.Destroy();
Hier guckt naemlich der Kompiler: Es soll die Methode Destroy von TObject aufgerufen werden. Diese Methode ist als virtual deklariert. Also gucken wir in der VMT nach. Weil diese aufgrund des Instanzierens durch TMeineKlasse.Create auf die VMT von TMeineKlasse geleitet wird, und der Eintrag von Destroy durch das override auf TMeineKlasse.Destroy() ueberschrieben wird, ruft der Kompiler auch TMeineKlasse.Destroy() auf -> Kein Speicherleck.

[Edit]Absatz entfernt. Er kam etwas persoenlich angreifender rueber als erhofft. Sorry, Klaerung per PN erfolgt.[/Edit]

greetz
Mike

Hansa 20. Feb 2007 01:50

Re: unsichtbare Klassen
 
Zitat:

Zitat von IngoD7
...Ich habe keinen Bock, dir zu erklären, dass das Gras grün ist...

Ingo, keiner zwingt dich dazu. Ich jedenfalls nicht. Es gibt Leute die ähnlich argumentieren würden, auch wenn das Gras in Wirklichkeeit rot wäre. :mrgreen:

Zitat:

Zitat von IngoD7
und wenn du eigenen Klassen immer einen statischen Destruktor verpasst und diesen immer direkt mit xxx.Destroy aufrufst, dann wirst du möglicherweise immer zurecht kommen.

Von statisch war keine Rede, es geht um Vererbung. Speziell von leeren Klassen und dem Sinn davon, diese sogar zu überschreiben. Um mehr geht es nicht. Vielleicht kommt ja noch zu meinen beiden letzten Beispielen ein Kommentar.

JasonDX 20. Feb 2007 01:56

Re: unsichtbare Klassen
 
Zitat:

Zitat von Hansa
Von statisch war keine Rede, es geht um Vererbung. Speziell von leeren Klassen und dem Sinn davon, diese sogar zu überschreiben. Um mehr geht es nicht. Vielleicht kommt ja noch zu meinen beiden letzten Beispielen ein Kommentar.

Verarschen kann ich mich selber. :roll: :
Zitat:

Zitat von Hansa
Gut, dann schmeiße ich das eigene Destroy mal selber raus.

:wall: Wenns kein Destroy braeuchte, gaebs auch kein Problem. Der Destruktor wird eben gebraucht, und es soll auch der destruktor von TMeineKlasse aufgerufen werden, wenn die variable zwar mit TMeineKlasse.Create instanziert, aber als TObject deklariert wurde.
Akzeptiere das einfach. Wenn dus verstehen willst, lies dir den Thread nochmal durch. Wenn dus dann immernoch nicht verstanden hast, dann beachte den letzten Absatz meines vorherigen Beitrages.

greetz
Mike

SirThornberry 20. Feb 2007 09:11

Re: unsichtbare Klassen
 
Könntet ihr bitte zurück zum Thema kommen (unsichtbare Klassen)?! Wenn ihr über Grundlagen der Objectorientierten Programmierung diskutieren wollt macht bitte einen eigenen Thread auf.

IngoD7 20. Feb 2007 09:28

Re: unsichtbare Klassen
 
Zitat:

Zitat von SirThornberry
Könntet ihr bitte zurück zum Thema kommen (unsichtbare Klassen)?! Wenn ihr über Grundlagen der Objectorientierten Programmierung diskutieren wollt macht bitte einen eigenen Thread auf.

Jetzt noch zum Thema zurück? :twisted: :wink:

Kannst du den Thread aufteilen und diesen Teil mit Titel "Warum virtuelle Destructoren?" (oder so ähnlich) abhängen? Wäre vielleicht ganz nützlich, dieses Offtopic hier zu Ontopic woanders zu machen. ;-)
Danke.

SirThornberry 20. Feb 2007 14:21

Re: unsichtbare Klassen
 
Zitat:

Zitat von IngoD7
Zitat:

Zitat von SirThornberry
Könntet ihr bitte zurück zum Thema kommen (unsichtbare Klassen)?! Wenn ihr über Grundlagen der Objectorientierten Programmierung diskutieren wollt macht bitte einen eigenen Thread auf.

Jetzt noch zum Thema zurück? :twisted: :wink:

Kannst du den Thread aufteilen und diesen Teil mit Titel "Warum virtuelle Destructoren?" (oder so ähnlich) abhängen? Wäre vielleicht ganz nützlich, dieses Offtopic hier zu Ontopic woanders zu machen. ;-)
Danke.

so eben probiert und irgendwas ist dabei total schief gegangen :oops: Jetzt fehlt der erste Beitrag vom eigentlichen Beitrag obwohl mehrere abgespalten werden sollten.

Elvis 20. Feb 2007 14:35

Re: Warum virtuelle Destructoren?
 
Öhm Jungs, ich glaube jeder von euch hat schon mindestens einmal in einem Thread mitgewirkt in dem versucht wurde dem großen H zu erklären was abstrakte Methoden sind, oder Interfaces, oder was-weiß-ich-nicht-alles.
Und ich glaube jeder von euch hat ab irgendeinem Punkt in diesen Threads aufgegeben. (Zwangsläufig, das große H weiß immer noch wofür abstrakte Methoden gut sind :zwinker: )

Warum gebt ihr nicht gleich von vornherein auf und antwortet einfach gar nicht mehr auf seine Fragen, die von seiner überheblicher Unwissenheit strotzen, dass sich mir die Eingeweide verknoten?
Man kann sich auch auf angenehmere Art Magengeschwüre zuziehen... :zwinker:

Cöster 20. Feb 2007 16:03

Re: Warum virtuelle Destructoren?
 
Ich gebe noch nich auf, sondern fange jetzt erst an. :mrgreen: Ich habe mich sehr über die Fortsetzung meines Threads unsichtbare Klassen amüsiert und möchte jetzt, wo er unter einem anderen Titel steht, auch meinen Senf dazu abgeben.

@Hansa:

Starte bitte eine Delphi-Anwendung mit folgendem Code:

Delphi-Quellcode:
unit Unit1;

interface

uses
   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
   StdCtrls;

type
   TForm1 = class(TForm)
      procedure FormCreate(Sender: TObject);
   private
      { Private-Deklarationen }
   public
      { Public-Deklarationen }
   end;

   TMeineKlasse = class
   public
      destructor Destroy;
   end;

var
   Form1: TForm1;

implementation

{$R *.DFM}

destructor TMeineKlasse.Destroy;
begin
   ShowMessage('Hey, Destruktor von TMeineKlasse wurde aufgerufen. ' +
      'Wenn diese Meldung gleich 2mal hintereinander kommt, ist es in der ' +
      'Tat absolut unnötig, Destruktoren mit override zu kennzeichnen.');
end;

procedure TForm1.FormCreate(Sender: TObject);
var
   MeineKlasse: TMeineKlasse;
   MeineKlasseObjekt: TObject;
begin
   MeineKlasse := TMeineKlasse.Create;
   MeineKlasse.Free;
   MeineKlasseObjekt := TMeineKlasse.Create;
   MeineKlasseObjekt.Destroy;
   ShowMessage('Wenn dies die erste oder zweite ausgegebene Meldung ' +
      'nach Programmstart ist, ist dies neben der unschönen Warnung, ' +
      'mit der mich der Compiler gerade die ganze Zeit nervt, ein weiterer ' +
      'Grund, Destruktoren zu overriden.');
end;

end.

shmia 20. Feb 2007 17:09

Re: Warum virtuelle Destructoren?
 
Ich gebe hier mal ein paar goldene Regeln vor.
An die Skeptiker hier: Ihr müsst das einfach als gegeben annehmen. Es wurde von Borland so designt.
Ich kann nur empfehlen, diese Regeln immer zu beachten. :warn: Ausdrucken, lesen und an den Monitor kleben...


1.) es gibt nur EINEN Destruktor! (Es kann nur einen geben)
Grund: ein Objekt kann auch ohne dass der Programmierer explizit der Destruktor aufgerufen hat, sterben.
Man denke hier nur an die Referenzzählung über COM Interfaces.
2.) der Destruktor muss immer Destroy heisen !
Pro Klasse darf man einen Destruktor namens Destroy deklarieren
3.) dagegen kann es beliebig viele Konstruktoren geben
4.) dieser eine Destruktor ist von Hause aus virtuell (und das hat seine Gründe und Vorteile, wie oben schon vor Einigen erklärt wurde)
Zusammen mit 1) bedeutet das, dass man keine neue Arten von Destruktoren einführen kann
5.) Innerhalb des Destruktors muss man grundsätzlich immer inherited als letzte Anweisung aufrufen.
Delphi-Quellcode:
destructor TMeinObjekt.destroy;
begin
   FInneresObj.Free;
   inherited;  // <= wer das vergisst, den holt der Speicherfresser !!!
end;
Jede Klasse räumt seine selbst belegten Resourcen ab und muss dann den Destruktor der ererbten Klasse aufrufen. TObject.Destroy gibt dann der Speicher für das Objekt frei.
6.) Destroy wird grundsätzlich niemals direkt aufgerufen; es muss Free benutzt werden
Delphi-Quellcode:
FMeinObjekt.Destroy; // <= so ist der Ärger vorprogrammiert (FMeinObjekt könnte nil sein) !!
FMeinObjekt.Free; // das ist ok
FreeAndNil(FMeinObjekt); // auch erlaubt aber mehr Overhead

// möglich (aber ziemlich blöd, da es ja Free gibt) wäre auch
if Assigned(FMeinObjekt) then FMeinObjekt.Destroy;
7.) der Destruktor muss mit Override deklariert werden; alles andere wäre falsch (dies erklärt sich aus 1.) und 4.))
Delphi-Quellcode:
TMeinObjekt = class(TPersistent)
public
   destructor Destroy;override;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:54 Uhr.
Seite 4 von 4   « Erste     234   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz