Newsgroup: it.comp.lang.delphi
Titolo: Classi e distruttore

Sto sperimentando le classi , e mi viene il dubbio su come distruggere un
oggetto; per avere il metodo free, devo dichiarare Gatto "nelle private";
oppure avere un distruttore:
  type
   TGatti=class(TAnimali)
   ....
   destructor Destroy;
  end;
.....
destructor TGatti.Destroy;
begin
 Free;
end;
e al FormClose chiamare Gatto.Destroy
quale via e' piu' corretta
Gatto.Destroy o Gatto.Free ?
ho  letto che il distruttore andrebbe usato se si usa il costruttore.
grazie Stefano
^^^^^^^^^^^^^
unit unt_Test;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, unt_Gatti;
type
  Tfrm_Test = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Edit1: TEdit;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    Gatto:TGatti;
  public
    { Public declarations }
  end;
var
  frm_Test: Tfrm_Test;
implementation
uses unt_Animali;
{$R *.dfm}
procedure Tfrm_Test.Button1Click(Sender: TObject);
begin
 try
  Gatto:=TGatti.Create;
  with Gatto do
  begin
   Edit1.Text:=Gatto.VersoAnimale;
  end;
 finally
 end;
end;
procedure Tfrm_Test.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Gatto.Free;
 Action:=caFree;
end;
procedure Tfrm_Test.FormCreate(Sender: TObject);
var Animale:TAnimali;
begin
 try
   Animale:=TAnimali.Create;
 finally
 end;
end;
end.
^^^^^^
unit unt_Gatti;
interface
uses unt_Animali;
  type
   TGatti=class(TAnimali)
   function VersoAnimale:String; override;
  end;
implementation
function TGatti.VersoAnimale:String;
begin
 Result:='miao, miao';
end;
end.

 Gatto.Destroy o Gatto.Free ?
Hai mescolato alcune cose: il modo giusto e' Gatto.Free
La convenzione in Delphi e' di non chiamare mai il distruttore 
direttamente, ma utilizzare il metodo Free, che e' sempre disponibile in 
ogni oggetto e che piu' o meno fa qualcosa di simile a (semplifico per 
maggiore chiarezza):
procedure TObject.Free;
begin
   if Self <> nil then
     Self.Destroy;
end;
Tra l'altro come si vede, e' sicuro anche eseguire Free di un 
riferimento a nil, a differenza di altri linguaggi dove sarebbe un errore.
Quindi quello che devi fare e' ridefinire il distruttore Destroy e 
soprattuto nel distruttore non devi chiamare Free altrimenti fai del danno!
ciao
Giacomo

Aggiungo solo due cosine:
1. nella tua classe, il metodo Destroy lo devi sovrascrivere richiamando 
l'inherited;
2. il metodo destroy non lo devi sovrascrivere sempre, ma solo se serve a 
distruggere in tempo oggetti creati all'interno della tua classe. Per 
esempio, se nella tua classe usi solo delle variabili, per esempio integer, 
anche se scrivi il costruttore create in cui inizializzi queste variabili, 
nel destroy non serve far nulla e puoi non sovrascriverlo. Se invece la tua 
classe usa (ad esempio) una TStrigList, che creerai in qualche momento, 
verosimilmente nel create della tua classe, allora devi sovrascrivere il 
destroy  facendo il free della stringlist prima di richiamare l'inherited 
del destroy stesso.
Gianni 

ho  letto che il distruttore andrebbe usato se si usa il costruttore.
Normalmente č cosě, ma nulla vieta di usare un distruttore pur senza
costruttore.

> costruttore.
per quanto gia' detto , e' sbagliato come facevo , usare Free dentro il
Destroy , ma come regola cosa si mette, oggetto:=Nil ?
destructor Destroy
begin
 ???? Gatto:=nil;
end;
grazie ancora delle indicazioni che mi avete dato. 

Destroy , ma come regola cosa si mette, oggetto:=Nil ?
No, non ha senso e non ha alcun effetto ai fini della "pulizia" di cui
parlavo.  Devi compiere tutte le operazioni di clean-up necessarie
(che dipendono da quanto hai utilizzato nel costruttore e durante la
vita dell'oggetto).  Se, ad esempio, nel costruttore alloco, nel
distruttore deallocherň:
type
  TMyClass = class(TMyBaseClass)
  private
    FMyStringList: TStringList;
  public
    constructor Create;
    destructor Destroy; override;
  end;
  ...
  constructor TMyClass.Create;
  begin
    inherited; // <-- invoco il costruttore di TMyBaseClass
    FMyStringList := TStringList.Create;   
  end;
  destructor TMyClass.Destroy;
  begin
    FMyStringList.Free;   
    inherited; <-- invoco il distruttore di TMyBaseClass
  end;
Prevedi anche che il distruttore possa agire in casi di costruzione
parziale di un oggetto, perché č possibile che si sollevino delle
eccezioni nel costruttore e quindi il sistema invoca *subito* il
distruttore.

riferimento a nil, a differenza di altri linguaggi dove sarebbe un errore.
E qui verrebbe da chiedersi: come si è potuto invocare il metodo di
un'istanza, se l'istanza è nil ?

http://makeashorterlink.com/?F19E35AED
Acqua 


http://makeashorterlink.com/?F19E35AED
Lo so bene come funziona Free(), ovviamente.  La domanda era retorica.
Il fatto è che non è intuitivo usare un metodo di un'istanza, quando
quell'istanza è già diventata nil.  Bada che ho detto "non intuitivo",
non errato.

 quell'istanza è già diventata nil.
Condivido pienamente.
Acqua