AW: Interessantes Destruktor Problem
Auch wenn es in diesem Beispiel geht, da ja Stream ein übergebener Parameter ist, sollte man die Reihenfolge konsequent einhalten.
Denn somst könnte es bei späteren Änderungen im Code zu Missverständnissen führen. Ich würde auch zudem keine "externen" Objekte in einem Konstruktor erzeugen. |
AW: Interessantes Destruktor Problem
Zitat:
Die Aussage "man sollte so nicht programmieren" kann ich also in keiner Weise nachvollziehen. Nur ein paar Beispiele aus Classes.pas:
Delphi-Quellcode:
destructor TRegGroup.Destroy;
destructor TThreadList.Destroy; destructor TStringList.Destroy; destructor TThread.Destroy; destructor TBasicAction.Destroy; destructor TDataModule.Destroy; |
AW: Interessantes Destruktor Problem
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TMyObject = class Private FMyTest:TStringList; function GetInfo: String; public destructor Destroy; override; Constructor Create;virtual; procedure FreeInstance; override; Property Info:String Read GetInfo; end; TMyObject2 = class(TMyObject) public destructor Destroy; override; Constructor Create;override; procedure FreeInstance; override; end; TForm1 = class(TForm) ADODataSet1: TADODataSet; Button1: TButton; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin With TMyObject2.Create do Free; end; { TMyObject } constructor TMyObject.Create; begin inherited; FMyTest:=TStringList.Create; FMyTest.Add('Text'); end; destructor TMyObject.Destroy; begin FMyTest.Free; inherited; end; procedure TMyObject.FreeInstance; begin inherited; end; function TMyObject.GetInfo: String; begin Result := FMyTest.Text; end; { TMyObject2 } constructor TMyObject2.Create; begin inherited; end; destructor TMyObject2.Destroy; begin Showmessage('Vor inherited:' +Info); inherited; Showmessage('Nach inherited:' +Info); end; procedure TMyObject2.FreeInstance; begin inherited; end; end. |
AW: Interessantes Destruktor Problem
Zitat:
Die Frage ist nicht warum man so etwas nicht tun sollte. Die Frage ist: Gibt es irgend einen Grund warum man sowas machen sollte? |
AW: Interessantes Destruktor Problem
@Bummi:
Und was soll uns der Code zeigen? @mleyen: Darum sollte man auch LERNEN wie etwas funktioniert, anstatt einfach irgendeine Aussage von wegen "Es muss so sein, frag nicht warum, es ist halt so!" zu glauben :roll: Und wenn man schon mit so einem Anfänger im Team arbeitet, gibt es ja noch die guten alten Kommentare, um zu erklären, warum hier etwas nach inherited steht obwohl das ja sooo böse ist. Und einen Grund gibt es auch, dass zu tun: Wenn man z.B. eine von Uwe Raabe genannte Klasse ableiten will, kann es u.U. unerlässlich sein. |
AW: Interessantes Destruktor Problem
Zitat:
|
AW: Interessantes Destruktor Problem
Zitat:
|
AW: Interessantes Destruktor Problem
Also ganz in Ordnung finde ich den Code auch nicht allerdings wegen etwas anderem.
Delphi-Quellcode:
Und zwar ist hier ersichtlich das der Constructor der Vorfahrenklasse einen Constructor hat dem ein Stream übergeben wird.
constructor TAbgeleiteteKlasse.Create;
begin FStream := TMemoryStream.Create; inherited Create(FStream); end; destructor TAbgeleiteteKlasse.Destroy; begin [...] FStream.Free; end; Auch wenn der Constructor der neuen Klasse diesen Parameter nicht mehr hat ist es trotzdem noch möglich den Constructor der Vorfahrenklasse aufzurufen und den Stream zu übergeben. In dem Fall ist es Fatal das im neuen Destructor einfach mein übergebener Stream frei gegeben wird. Bsp.:
Delphi-Quellcode:
Also ein eindeutiger Designfehler. Das worüber hier die ganze Zeit diskutiert wird kann ich nicht nachvollziehen denn es ist tatsächlich ab und zu der Fall das man erst nach dem inherited im Destructor etwas freigeben kann. Das ist zum Beispiel der Fall wenn im Destructor der Klasse von der man ableitet noch OnChange-Ereignisse/Speichern-Methoden etc. aufgerufen werden die durch Vererbung Dinge aus dem Nachfahren verwenden.
var
mystream: TStream; tmp: TAbgeleiteteKlasse; begin MyStream := TMemoryStream.Create(); tmp := TAbgeleiteteKlasse.Create(myStream); [...] tmp.Free; //jetzt ist plötlizlich mystream freigegeben obwohl das bei der Vorfahrenklasse noch nicht der Fall war [...] |
AW: Interessantes Destruktor Problem
@SirThornberry:
Es war ja auch nur ein Beispiel, was mir im damaligen Thread spontan eingefallen ist. Über Sinn oder Unsinn einen Konstruktor derart zu überschreiben ging es bei der Diskussion aber auch nie :wink: PS: Der "alte" Konstruktor, der den Stream erwartet, könnte z.B. (strict) protected sein, so kann man ihn nicht so aufrufen, wie in deinem Beispiel ... |
AW: Interessantes Destruktor Problem
Achso. Auf jeden Fall ist an dem diskutierten nichts verwerfliches. Wie bereits beschrieben wird der Speicher schließlich vorm Constructor-Aufruf reserviert und nach dem Destructor-Aufruf freigegeben. Und auch in anderen Programmiersprachen ist das nicht viel anders.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:58 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