Delphi-PRAXiS

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)

Muetze1 18. Feb 2007 00:06


Re: unsichtbare Klassen
 
1. Entweder einfach im Implementation Teil deklararieren.
2. Oder als private Sub-Klasse definieren
3. Auslagern und diese Unit Unit-privat im Implementation Teil einbinden

Diese Möglichkeiten sehe ich ...

Cöster 18. Feb 2007 00:49

Re: unsichtbare Klassen
 
Zitat:

Zitat von Muetze1
1. Entweder einfach im Implementation Teil deklararieren.

Hört sich schonmal gut an, krieg ich aber irgendwie nicht richtig gebacken. Ich hab die Deklaration von TNode einfach unter "implementation" verschoben und noch type davor geschrieben. Dann fängt's allerdings schon damit an, dass TNode (was der Typ einiger Attribute TFIFOs ist) ein undefinierter Bezeichner ist. Zahlreiche weitere Fehlermeldungen folgen.

Zitat:

Zitat von Muetze1
2. Oder als private Sub-Klasse definieren

:wiejetzt: TNode von TFIFO ableiten? Und dann? Den Typen TNode muss ich bereits in TFIFO verwenden können, da er wie gesagt Typ einiger Attribute dort ist. :gruebel: Was genau ist eine private Subklasse?

Ich zeig am besten mal den Code, wie er bisher war:

Delphi-Quellcode:
unit FIFO;

interface

type
   TNode = class
   private
      FNext: TNode;
      FObject: TObject;
      constructor Create(AObject: TObject);
      destructor Destroy; override;
   end;

   TFIFO = class
   private
      FFront: TNode;
      FRear: TNode;
   public
      constructor Create;
      destructor Destroy; override;
      procedure Clear;
      function Dequeue: TObject;
      procedure Enqueue(AObject: TObject);
   end;

implementation


constructor TNode.Create(AObject: TObject);
begin
   inherited Create;
   FObject := AObject;
   FNext := nil;
end;

destructor TNode.Destroy;
begin
   FObject.Free;
   inherited;
end;

constructor TFIFO.Create;
begin
   inherited;
   FFront := nil;
   FRear := nil;
end;

destructor TFIFO.Destroy;
begin
   Clear;
   inherited;
end;

procedure TFIFO.Clear;
begin
   while FFront <> nil do
      Dequeue.Free;
end;

function TFIFO.Dequeue;
begin
   if FFront <> nil then
   begin
      Result := FFront.FObject;
      FFront := FFront.FNext;
   end
   else
      Result := nil;
end;

procedure TFIFO.Enqueue(AObject: TObject);
begin
   if FRear <> nil then
   begin
      FRear.FNext := TNode.Create(AObject);
      FRear := FRear.FNext;
   end
   else
   begin
      FRear := TNode.Create(AObject);
      FFront := FRear;
   end;
end;

end.
Wie genau müsste ich den dann umschreiben?

Muetze1 18. Feb 2007 02:59

Re: unsichtbare Klassen
 
Zitat:

Zitat von Cöster
Zitat:

Zitat von Muetze1
1. Entweder einfach im Implementation Teil deklararieren.

Hört sich schonmal gut an, krieg ich aber irgendwie nicht richtig gebacken. Ich hab die Deklaration von TNode einfach unter "implementation" verschoben und noch type davor geschrieben. Dann fängt's allerdings schon damit an, dass TNode (was der Typ einiger Attribute TFIFOs ist) ein undefinierter Bezeichner ist. Zahlreiche weitere Fehlermeldungen folgen.

Das ist klar. Von daher musst du es bei diesem Weg eh so umschreiben, dass TNode nur intern genutzt wird und nur in der Implementation entsprechend ge-typecasted wird.

Zitat:

Zitat von Cöster
Zitat:

Zitat von Muetze1
2. Oder als private Sub-Klasse definieren

:wiejetzt: TNode von TFIFO ableiten? Und dann? Den Typen TNode muss ich bereits in TFIFO verwenden können, da er wie gesagt Typ einiger Attribute dort ist. :gruebel: Was genau ist eine private Subklasse?

Ich habe nix von ableiten geschrieben.

Delphi-Quellcode:
unit FIFO;

interface

type
  TFIFO = class
  private
    Type
      TNode = class
      private
        FNext: TNode;
        FObject: TObject;

      public
        constructor Create(AObject: TObject);
        destructor Destroy; override;
      end;

  private

      FFront: TNode;
      FRear: TNode;
   public
      constructor Create;
      destructor Destroy; override;
      procedure Clear;
      function Dequeue: TObject;
      procedure Enqueue(AObject: TObject);
   end;

implementation


constructor TNode.Create(AObject: TObject);
begin
   inherited Create;
   FObject := AObject;
   FNext := nil;
end;

destructor TNode.Destroy;
begin
   FObject.Free;
   inherited;
end;

constructor TFIFO.Create;
begin
   inherited;
   FFront := nil;
   FRear := nil;
end;

destructor TFIFO.Destroy;
begin
   Clear;
   inherited;
end;

procedure TFIFO.Clear;
begin
   while FFront <> nil do
      Dequeue.Free;
end;

function TFIFO.Dequeue;
begin
   if FFront <> nil then
   begin
      Result := FFront.FObject;
      FFront := FFront.FNext;
   end
   else
      Result := nil;
end;

procedure TFIFO.Enqueue(AObject: TObject);
begin
   if FRear <> nil then
   begin
      FRear.FNext := TNode.Create(AObject);
      FRear := FRear.FNext;
   end
   else
   begin
      FRear := TNode.Create(AObject);
      FFront := FRear;
   end;
end;

end.
/EDIT: Programmierst du wirklich mit TABs? Das gehört meiner Meinung nach verboten...

/EDIT2: Den Constructor und Desctructor kannst du nicht einfach in eine geringere Sichtbarkeit verschieben...

Cöster 18. Feb 2007 12:55

Re: unsichtbare Klassen
 
Zitat:

Zitat von Muetze1
Ich habe nix von ableiten geschrieben.

Dann war mir bis gerade der Begriff Subklasse wohl nicht ganz klar. Jetzt weiß ich, was du meinst, und werde es mit diesen "privaten Subklassen" machen. Bei der Implementierung der Subklassen-Methoden muss ich im Methodenkopf vor "TNode" dann aber wohl auch noch "TFIFO." ergänzen.

Zitat:

Zitat von Muetze1
Programmierst du wirklich mit TABs? Das gehört meiner Meinung nach verboten...

Ja, warum nicht? Dazu gab's hier ja schon mehrere Diskussionen, die mich überzeugt haben 3 Zeichen lange Tabs zu verwenden.
Aber falls du einen guten Grund dagegen hast, würd ich den gerne hören (falls es hier zu OT wird, dann evtl per PM oder im verlinkten Thread.

blawen 18. Feb 2007 13:27

Re: unsichtbare Klassen
 
Zitat:

Zitat von Muetze1
Programmierst du wirklich mit TABs? Das gehört meiner Meinung nach verboten...

Zitat:

Zitat von Cöster
Ja, warum nicht? Dazu gab's hier ja schon mehrere Diskussionen, die mich überzeugt haben 3 Zeichen lange Tabs zu verwenden.
Aber falls du einen guten Grund dagegen hast, würd ich den gerne hören (falls es hier zu OT wird, dann evtl per PM oder im verlinkten Thread.

Siehe hier

Muetze1 18. Feb 2007 22:17

Re: unsichtbare Klassen
 
Zitat:

Zitat von Cöster
Zitat:

Zitat von Muetze1
Programmierst du wirklich mit TABs? Das gehört meiner Meinung nach verboten...

Ja, warum nicht? Dazu gab's hier ja schon mehrere Diskussionen, die mich überzeugt haben 3 Zeichen lange Tabs zu verwenden.
Aber falls du einen guten Grund dagegen hast, würd ich den gerne hören (falls es hier zu OT wird, dann evtl per PM oder im verlinkten Thread.

Ja, der Grund, der mich zu der Frage führte: ich hatte Probleme den gequoteten Quellcode abzuändern, ohne das meine Ergänzungen völlig falsch eingerückt waren. Auch ist Tab schlecht in Bezug auf editieren, weil man(n) erstmal wissen muss, dass du einen 3 Zeichen Tab verwendest. Ansonsten steht der Rest in dem von blawen verlinkten Beitrag. Für mich war es deutlich umständlicher den Quellcode anzupassen...

Cöster 18. Feb 2007 23:29

Re: unsichtbare Klassen
 
Zitat:

Zitat von Muetze1
ich hatte Probleme den gequoteten Quellcode abzuändern, ohne das meine Ergänzungen völlig falsch eingerückt waren. Auch ist Tab schlecht in Bezug auf editieren, weil man(n) erstmal wissen muss, dass du einen 3 Zeichen Tab verwendest.

Dann werd ich, bevor ich hier das nächste Mal Code poste, vorher daran denken, meine Tabs in Leerzeichen umzuwandeln. Wenn die Tab-Breite im Antwort-schreiben-Fenster auf 8 erhöht wird, könnte es tatsächlich etwas unübersichtlich werden.

Zitat:

Zitat von Muetze1
Für mich war es deutlich umständlicher den Quellcode anzupassen...

Dann erst Recht vielen Dank für deine Hilfe :thumb:

Hansa 19. Feb 2007 00:33

Re: unsichtbare Klassen
 
Ja, Tabs sind echt schön. :mrgreen: Trotzdem Zwischenfrage : wozu konkret dient das zweimalige "override" ? :shock:

JasonDX 19. Feb 2007 00:38

Re: unsichtbare Klassen
 
Zitat:

Zitat von Hansa
Zwischenfrage : wozu konkret dient das zweimalige "override" ? :shock:

Wo siehst du ein zweimaliges Override? Einmal isses fuer TFIFO.Destroy, und einmal fuer TNode.Destroy. Nicht durch die Nested Classes durcheinanderbringen lassen :zwinker:

greetz
Mike

Hansa 19. Feb 2007 00:44

Re: unsichtbare Klassen
 
Ja, was soll denn überschrieben werden ? :shock: Da ist doch nichts vorher.

JasonDX 19. Feb 2007 00:54

Re: unsichtbare Klassen
 
Zitat:

Zitat von Hansa
Ja, was soll denn überschrieben werden ? :shock: Da ist doch nichts vorher.

Ich weiss ja nicht, wie's bei dir aussieht, aber mein TObject hat sowas drinstehn:
Delphi-Quellcode:
destructor Destroy; virtual;
;)

greetz
Mike

Hansa 19. Feb 2007 01:04

Re: unsichtbare Klassen
 
Jason, ich meine das hier :

Delphi-Quellcode:
type
  TFIFO = class
        destructor Destroy; override;
      end;
Delphi wird das schon schlucken. Nur, was soll das ?

JasonDX 19. Feb 2007 01:15

Re: unsichtbare Klassen
 
Zitat:

Zitat von Hansa
Nur, was soll das ?

So wies aussieht soll das den virtuellen Destruktor ueberschreiben. :stupid:

greetz
Mike

Hansa 19. Feb 2007 01:25

Re: unsichtbare Klassen
 
Dann zeige mal wo der sein soll. :zwinker: Mittlerweile auch gemerkt, dass da was nicht stimmt ? :mrgreen: Oder, was habe ich in Object-Pascal wann verpasst ?

Dax 19. Feb 2007 01:31

Re: unsichtbare Klassen
 
In TObject? :gruebel:

JasonDX 19. Feb 2007 01:31

Re: unsichtbare Klassen
 
Zitat:

Zitat von Hansa
Dann zeige mal wo der sein soll. :zwinker:

Spielen wir grad blinde Kuh? :gruebel:
Hier hab ichs schon mal geschrieben: TObject enthaelt einen virtuellen Destruktor:
Delphi-Quellcode:
Type
  TObject = Class
  Public
    destructor destroy;virtual;
greetz
Mike

Hansa 19. Feb 2007 01:46

Re: unsichtbare Klassen
 
Blinde Kuh ? Ja wär doch gut. :lol:

Nächster Versuch :

Delphi-Quellcode:
type
  TFIFO = class
  private
    Type
      TNode = class
      private
        FNext: TNode;
        FObject: TObject;

      public
        constructor Create(AObject: TObject);
        destructor Destroy; override;
      end;
Erkläre mir mal bitte, warum da ein Destructor einer leeren Class TFIFO (also ohne Vorfahr) per override überschrieben werden muss. Mehr will ich gar nicht wissen. Wer soll mit dem "override" denn überhaupt angesprochen werden ? :shock:

JasonDX 19. Feb 2007 01:49

Re: unsichtbare Klassen
 
Zitat:

Zitat von Hansa
Erkläre mir mal bitte, warum da ein Destructor einer leeren Class TFIFO (also ohne Vorfahr) per override überschrieben werden muss. Mehr will ich gar nicht wissen. Wer soll mit dem "override" denn überhaupt angesprochen werden ? :shock:

Wenn nicht anders angegeben, wird jede Klasse von TObject abgeleitet und erbt damit all ihre Methoden. Inklusive dem virtuellen Destruktor, der dann ueberschrieben wird.

gute Nacht
Mike

Muetze1 19. Feb 2007 02:30

Re: unsichtbare Klassen
 
Ich hänge dazu nochmal schnell die Meinung der OH an, welches dies auch ausdrücklich beschreibt:
Zitat:

Zitat von oh
Wenn Sie in der Deklaration eines Klassentyps keinen Vorfahren angegeben, erbt die Klasse direkt von TObject. Aus diesem Grund ist die Deklaration

Delphi-Quellcode:
TMyClass = class
 ...
end;
identisch mit

Delphi-Quellcode:
type TMyClass = class(TObject)
 ...
end;
Die zweite Variante verdient jedoch aus Gründen der Lesbarkeit den Vorzug.

@Hansa: Bei C++ bzw. speziell dem BCB wäre es wichtig bzw. ein Unterschied für die VCL Klassen bzw. C++ Klassen. Diese können auch nicht vermischt werden, aber in Delphi gibt es immer nur die VCL Klassen, und die erben grundsätzlich von TObject, wenn nicht explizit anders angegeben.

/EDIT: Wenn du das Override nicht angibst, dann erhälst du zum einen einen Hinweis/Warnung vom Compiler und zum anderen wird dein Destructor nie ausgeführt.

IngoD7 19. Feb 2007 09:09

Re: unsichtbare Klassen
 
Zitat:

Zitat von Muetze1
/EDIT: Wenn du das Override nicht angibst, dann erhälst du zum einen einen Hinweis/Warnung vom Compiler und zum anderen wird dein Destructor nie ausgeführt.

Das bedarf aber noch ein paar Erklärungen. ;-)

Er wird nur dann nicht ausgeführt, wenn zum Freigeben von TMeinObjekt ein MeinObjekt.Free benutzt wird. Free ist von TObject geerbt und ruft eben nur den Destruktor destroy von TObject auf, wenn dessen Virtualität nicht Rechnung getragen wird in den abgeleiteten Klassen. Durch ein override würde MeinObjekt.Free den Destructor destroy von TMeinObjekt aufrufen. Daher sollten Destruktoren in der Regel immer ihren Ahnen per override überschreiben. Eben weil sonst ein Free den eigenen Destruktor nicht "erreichen" würde, sondern in TObject "hängenbleiben" würde.

Nun kann man aber locker auch den Destruktor direkt aufrufen, um ein TMeinObjekt freizugeben: MeinObjekt.Destroy.
In diesem Fall würde der Destruktor von TMeinObjekt immer aufgerufen werden, ohne jegliche Relevanz dessen, ob er seinen Ahnen in TObject überschreibt oder nicht.
Allerdings ist diese Art des Destruktoren-Aufrufs nicht sooo sonderlich empfehlenswert, weil zuvor überprüft werden muss, ob MeinObjekt nicht schon nil ist. Nichts anderes macht nämlich TObject.Free. :-)

Muetze1 19. Feb 2007 09:12

Re: unsichtbare Klassen
 
gleiches gilt neben dem Aufruf von xxx.Free; auch für die Verwendung/Aufruf von FreeAndNil(xxx);

Hansa 19. Feb 2007 18:42

Re: unsichtbare Klassen
 
Vorab : der Thread hier wurde vom Fragesteller woanders mittlerweile als OT gebrandmarkt. :mrgreen:

Nichtsdestotrotz : das ganze sieht doch so aus :

Delphi-Quellcode:
destructor TObject.Destroy;
begin
end;
Wie Muetze richtig aus der Hilfe zitiert hat, ist es dasselbe einfach "class" zu schreiben oder eben "class (TObject)". Also ist das ein Nachfahre von TObject. Aber nur pro forma. Warum soll jetzt da nochmals ein leerer Destructor per override auch noch überschrieben werden ? :shock: Vermute sogar, dass der Delphi-Linker das automatisch entfernt. Naheliegend wäre auch, das die vereinfachte Schreibweise Class erlaubt wird, damit keiner auf die Idee kommt, so was überflüssigerweise zu machen. :-D

JasonDX 19. Feb 2007 19:09

Re: unsichtbare Klassen
 
Zitat:

Zitat von Hansa
Also ist das ein Nachfahre von TObject. [...] Warum soll jetzt da nochmals ein leerer Destructor per override auch noch überschrieben werden ? :shock:

Hmm, ein paar OOP-Tutorials wuerden dir nicht schlecht tun:
Du hast eine beliebige Klasse, bspw. TMeineKlasse. Im Konstruktor dieser Klasse wird bspw. Speicher allociert, oder irgendetwas instanziert, das im Destruktor wieder freigegeben werden muss.
Nun gibts 2 Moeglichkeiten:
Delphi-Quellcode:
//1.
destructor Destroy();
//2.
destructor Destroy(); override;
Du behauptest, zweiteres mache keinen Sinn. Analysieren wir mal, was die unterschiede sind:
Wenn eine Variable als TMeineKlasse deklariert ist, macht es keinen Unterschied.
Wenn aber eine Variable nicht als TMeineKlasse, sondern als Vorfahre (bspw. TObject) deklariert ist, aber als TMeineKlasse instanziert wurde, muss auch der Destruktor von TMeineKlasse aufgerufen werden.
Passiert das aber? Nein.
Delphi-Quellcode:
TMeineKlasse = class
  constructor Create();
  destructor Destroy();
  speicher: Pointer;
end;
//...
constructor TMeineKlasse.Create();
begin
  speicher = allocmem(100);
end;

destructor TMeineKlasse.Create();
begin
  freemem(speicher);
end;



procedure ProbiersAus();
var
  x: TObject;
begin
  x := TMeineKlasse.Create();
  x.Free(); //Es wird TObject.Free aufgerufen!
end;
Gibt ein schoenes Speicherleck. mit dem ueberschreiben des Destruktors passiert das nicht.

greetz
Mike

Muetze1 19. Feb 2007 19:10

Re: unsichtbare Klassen
 
Zitat:

Zitat von Hansa
Warum soll jetzt da nochmals ein leerer Destructor per override auch noch überschrieben werden ?

Weil sonst sein FObject.Free bzw. das Clear nicht aufgerufen wird in seinem Constructor. Das Override ist notwendig, sonst wird der Destructor in der Ableitung nicht aufgerufen (siehe vorherige Ausführungen). Der Destructor in TObject ist leer, ok, aber dann könntest du vllt. propagandieren, dass der Inherited Aufruf weggelassen werden könnte - das stimmt, aber das Override ist notwendig für den Aufruf.

Den Aufruf von Inherited würde ich aber auch nicht weglassen, da sonst bei einer Änderung des Inhalts des Destructors in TObject seitens Borlands nicht Rechnung getragen würde.

/EDIT: roter Rahmen verzweifelt gesucht...

IngoD7 19. Feb 2007 20:13

Re: unsichtbare Klassen
 
Zitat:

Zitat von Hansa
Warum soll jetzt da nochmals ein leerer Destructor per override auch noch überschrieben werden ? :shock:

Deshalb:

Zitat:

Zitat von IngoD7
Zitat:

Zitat von Muetze1
/EDIT: Wenn du das Override nicht angibst, dann erhälst du zum einen einen Hinweis/Warnung vom Compiler und zum anderen wird dein Destructor nie ausgeführt.

Das bedarf aber noch ein paar Erklärungen. ;-)

Er wird [...] nicht ausgeführt, wenn zum Freigeben von TMeinObjekt ein MeinObjekt.Free benutzt wird. Free ist von TObject geerbt und ruft eben nur den Destruktor destroy von TObject auf, wenn dessen Virtualität nicht Rechnung getragen wird in den abgeleiteten Klassen. Durch ein override würde MeinObjekt.Free den Destructor destroy von TMeinObjekt aufrufen. Daher sollten Destruktoren in der Regel immer ihren Ahnen per override überschreiben. Eben weil sonst ein Free den eigenen Destruktor nicht "erreichen" würde, sondern in TObject "hängenbleiben" würde.
[...]

Probiere es aus. :)

IngoD7 19. Feb 2007 20:26

Re: unsichtbare Klassen
 
@JasonDX

Zitat:

Zitat von JasonDX
Wenn eine Variable als TMeineKlasse deklariert ist, macht es keinen Unterschied.

Doch. Bei Benutzung von Free macht es immer einen Unterschied. Es gibt in der Regel nur das eine, geerbte Free in TObject. Das wird auch angesprungen wenn ein TMeineKlasse.Free aufgerufen wird. Und dieses angesprungenen TObject.Free würde jetzt nur den eigenen Destructor (in TObject) aufrufen, wenn der Destructor der abgeleiteten Klasse TMeineKlasse kein override besitzt. Und das eben auch bei
Delphi-Quellcode:
var
  x: TMeineKlasse;
Dieser "Umweg" über das Free, welches nur im Urahnen TObject existiert, macht beim Aufruf des Destructors den kleinen Unterschied.

Hansa 19. Feb 2007 20:34

Re: unsichtbare Klassen
 
Ich liebe Grundsatzdiskussionen, aber wir sind anscheinend noch lange nicht fertig. :mrgreen:

Erkläre mir mal bitte einer, was ich in diesem Fall mit dem overrride soll :
Delphi-Quellcode:
Unit Unit2;

interface

implementation

uses
  Dialogs,
  SysUtils;

type

TMeineKlasse = class
  private
    i : integer;
  protected
    constructor Create;
    destructor Destroy;
end;

var MeineKlasse : TMeineKlasse;

constructor TMeineKlasse.Create;
begin
  i := 123;
end;

destructor TMeineKlasse.Destroy;
begin
showmessage ('Destroy '+IntToStr (i));
end;

begin
  MeineKlasse := TMeineKlasse.Create;
showmessage (IntToStr (MeineKlasse.i));
  MeineKlasse.Destroy;
end.
Das Programm zeigt 2-mal '123' an, wie erwartet. Geht man dann noch hin und macht das IMHO überflüssige Destroy und alles was damit zusammenhängt weg, dann tut es das auch.

Wer hat ein Gegenbeispiel ? Es darf aber wirklich nur als Class deklariert sein. Das TObject-Free von Jason ist auch gemogelt, es geht um Destroy. Free hat eingebaute Funktionalität. Das ist schon was anderes.

IngoD7 19. Feb 2007 20:51

Re: unsichtbare Klassen
 
Moin Hansa,

das ist ungefähr das, was JasonDX meinte. Der direkte Aufruf von Destroy in deinem Beispiel verhält sich so, wie du sagst. Was anderes hatte JasonDX auch nicht behauptet.

Jetzt gibt es aber Fälle, wo (jetzt bezogen auf dein Beispiel) nicht
Delphi-Quellcode:
var MeineKlasse : TMeineKlasse;
sondern
Delphi-Quellcode:
var MeineKlasse : TObject;
gesetzt wird, und dennoch wie folgt created wird:
Delphi-Quellcode:
MeineKlasse := TMeineKlasse.Create;
Jetzt erreicht dein Code den Destructor von TMeineKlasse nicht mehr.

Zitat:

Zitat von Hansa
Das TObject-Free von Jason ist auch gemogelt, es geht um Destroy. Free hat eingebaute Funktionalität. Das ist schon was anderes.

Aber genau das ist gemeint!
Wer ruft denn bitteschön Destroy direkt auf? Für dein Beispiel war es jetzt ja ganz gut und schön und anschaulich. Aber in der Praxis sollte und wird die Methode Free oder die Procedure FreeAndNil() benutzt. Und genau dann ist override in jedem Fall erforderlich.

Hansa 19. Feb 2007 22:34

Re: unsichtbare Klassen
 
Zitat:

Zitat von IngoD7
das ist ungefähr das, was JasonDX meinte. Der direkte Aufruf von Destroy in deinem Beispiel verhält sich so, wie du sagst. Was anderes hatte JasonDX auch nicht behauptet.
...

Gut, dann schmeiße ich das eigene Destroy mal selber raus. Da ist nicht mehr viel zu entfernen.

Delphi-Quellcode:
Unit Unit2;

interface

implementation

uses
  Dialogs,
  SysUtils;

type

TMeineKlasse = class
  private
    i : integer;
    constructor Create;
end;

var MeineKlasse : TMeineKlasse;

constructor TMeineKlasse.Create;
begin
  i := 123;
end;

begin
  MeineKlasse := TMeineKlasse.Create;
showmessage (IntToStr (MeineKlasse.i));
end.
Kein Destroy mehr, auch kein override und es geht immer noch. Ich will lediglich wissen, was einige hier vorhaben mit override etc. Und sieh mal einer an, was steht denn da :

Delphi-Quellcode:
constructor TObject.Create;
begin
end;
:shock: Da ist ja sogar das Create eventuell fällig. :mrgreen:

Edit : es sei angemerkt, dass nicht mal inherited verwendet wird ! Normalerweise wäre das schon nötig.

IngoD7 19. Feb 2007 22:53

Re: unsichtbare Klassen
 
Zitat:

Zitat von Hansa
Zitat:

Zitat von IngoD7
das ist ungefähr das, was JasonDX meinte. Der direkte Aufruf von Destroy in deinem Beispiel verhält sich so, wie du sagst. Was anderes hatte JasonDX auch nicht behauptet.
...

Gut, dann schmeiße ich das eigene Destroy mal selber raus. Da ist nicht mehr viel zu entfernen.

Darum geht es doch gar nicht.

Du willst wissen, wie es sich mit virtuellen Methoden und override verhält? Fein. Steht hier in diesem Thread jetzt doppelt und dreifach. Lies in. ;-) In der Hilfe steht das ebenfalls recht ansprechend beschrieben. Die Geschichte mit Free ist zudem ein sehr schönes Beispiel für die Implemetierung in einer Klassenhierarchie. Kann man herrlich ausprobieren und (auch wenn's schwer ist) verstehen. Tue es, oder lass es. Ich habe keinen Bock, dir zu erklären, dass das Gras grün ist.

Wenn du jede Klasse ausschließlich so instantiierst wie sie deklariert ist 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.

Oder um auf das Gras zurückzukommen: Wenn du dein ganzen Grundstück zupflasterst, ist das in Ordnung. Die Rasenflächen der Anderen sind aber immer noch grün - ganz egal, ob du das akzeptierst oder nicht. :spin2:

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:01 Uhr.

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