![]() |
Re: unsichtbare Klassen
So, jetzt nochmal gaaaaaanz laaaaangsam, und schoooooeeen detailliert:
Regeln:
So, und nun was passiert: Gegeben sei folgende Klasse
Delphi-Quellcode:
und diese 2 Variablen:
TMeineKlasse = class(TObject)
constructor Create(); destructor Destroy(); //override; end;
Delphi-Quellcode:
welche beide mit
var
meineKlasseObject: TObject; meineKlasse: TMeineKlasse;
Delphi-Quellcode:
initialisiert werden.
TMeineKlasse.Create();
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:
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.
meineKlasse.Destroy();
nun
Delphi-Quellcode:
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).
meineKlasseObject.Destroy();
so, und nun das ganze mit override: beim aufruf von
Delphi-Quellcode:
veraendert sich nichts. Der Kompiler sieht immernoch die Methode TMeineKlasse.Destroy() (weil meineKlasse als TMeineKlasse deklariert ist), und ruft dementsprechend auch TMeineKlasse.Destroy() auf.
meineKlasse.Destroy
Der Unterschied kommt bei
Delphi-Quellcode:
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.
meineKlasseObject.Destroy();
[Edit]Absatz entfernt. Er kam etwas persoenlich angreifender rueber als erhofft. Sorry, Klaerung per PN erfolgt.[/Edit] greetz Mike |
Re: unsichtbare Klassen
Zitat:
Zitat:
|
Re: unsichtbare Klassen
Zitat:
Zitat:
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 |
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.
|
Re: unsichtbare Klassen
Zitat:
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. |
Re: unsichtbare Klassen
Zitat:
|
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: |
Re: Warum virtuelle Destructoren?
Ich gebe noch nich auf, sondern fange jetzt erst an. :mrgreen: Ich habe mich sehr über die Fortsetzung meines Threads
![]() @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. |
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:
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.
destructor TMeinObjekt.destroy;
begin FInneresObj.Free; inherited; // <= wer das vergisst, den holt der Speicherfresser !!! end; 6.) Destroy wird grundsätzlich niemals direkt aufgerufen; es muss Free benutzt werden
Delphi-Quellcode:
7.) der Destruktor muss mit Override deklariert werden; alles andere wäre falsch (dies erklärt sich aus 1.) und 4.))
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;
Delphi-Quellcode:
TMeinObjekt = class(TPersistent)
public destructor Destroy;override; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:04 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