Newsgroup: it.comp.lang.delphi
Titolo: problemi con classe

Descrivo un classe
  Type
       TMyClass = class(TPersistent)
       private
           FMember: String;
       protected
           FSaved: Boolean;
           procedure SetMember(const Value: String);
       public 
           constructor Create;
           property Memeber: String read FMember write SetMemeber;  
           property Saved: Boolean read FSaved;
       end;
constructor TMyClass .Create;
begin
  FMember := EmptyStr;
  FSaved := True;
end;
procedure TMyClass.SetMember(const Value: String);
begin
   if not SameText(Value, FMember) then
     FSaved := False;
   FMember := Value;
end;
In una form in cui posizione un due Controlli un TEdit e un TButton(prop
Enabled = False)
nell'evento On Exit del TEdit scrivo
procedure TForm.EditExit(Sender: TObject);
begin
  {istanza di TMyClass che ho creato nell'evento OnCreate}
  MyClass.Member := Edit.Text;
  if not MyClass.Saved then
    Button.Enabled := True;
end;
Io popolo l'istanza di TMyClass le assegno dei valori alla proprietą
Member nell'OnCreate della form ( e qui setto FSaved a True)
e quindi assegni il valore di MyClass.Member a Edit.Text (sempre con
FSaved = True)
La domanda per cui vorrei un  aiuto č semplice:
come mai se io scateno l'evento OnExit del TEdit FSaved risulta False
nonostante io non abbia modificato alcun valore?????
e nel debug FMember  dopo l'assegnamento al TEdit.Text risulta uguale a
''  ???
grazie FX alfio
P.S.: spero di non essere OT
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

)

 begin
    inherited Create;


     inherited Create;
perchè mai? La sua classe deriva da TPersistent che non ha un 
costruttore virtuale chiamato Create, nè tantomeno questo costruttore 
è presente in TObject...
Quella chiamata a inherited è perfettamente inutile, IMHO.
-- 
Andrea Magni

 Quella chiamata a inherited č perfettamente inutile, IMHO.
...ma diviene obbligatoria in Delphi .NET. :-)
Dovrň cominciare a perdere qualche cattiva abitudine... ;-)


 Dovrň cominciare a perdere qualche cattiva abitudine... ;-)
Anch'io allora... ;-)
-- 
Andrea Magni

 Perchč? hanno cambiato TObject.Create ?
Dall'eBook di Cantů su Delphi 8, pare che nell'implementazione di 
ciascun metodo costruttore sia obbligatorio richiamare il metodo 
ereditato (tramite la parola chiave *inherited*), mentre sino ad ora si 
poteva omettere ad esempio per i discendenti diretti di TObject, anche 
se sono concorde nel ritenere la forma di Delphi 8 piů corretta perchč 
elimina qualsiasi ambiguitŕ.


 è presente in TObject...
Il costruttore Create (statico) è presente in TObject (benché sia solo
uno stub vuoto) ed ereditato da TPersistent.
Posso essere d'accordo che la chiamata è inutile perché non esiste un
codice a monte da eseguire, ma non è inutile, a prescindere.
Oltretutto, utilizzare "inherited" solo nel caso dei costruttori
virtuali è fondamentalmente *errato*.
Quando si eredita una classe figlia da una classe madre, bisogna
SEMPRE, per logica, inizializzare lo stato della classe figlia,
ereditato dalla classe madre, PRIMA di fare qualsiasi operazione.
Dimmi se, secondo la tua opinione, il codice seguente da' un risultato
corretto:
type
  MyBaseClass = class
  private
    FMyProperty: Integer;
  public
    constructor Create;
  end;
  MyDerivedClass = class(MyBaseClass)
  public
    constructor Create;
    procedure ShowValues;
  end;
procedure TForm1.Button1Click(Sender: TObject);
begin
  with MyDerivedClass.Create do
    ShowValues
end;
{ MyBaseClass }
constructor MyBaseClass.Create;
begin
  FMyProperty := 42;
end;
{ MyDerivedClass }
constructor MyDerivedClass.Create;
begin
  //  inherited;  (commento l'inherited)
end;
procedure MyDerivedClass.ShowValues;
begin
  ShowMessage(IntToStr(FMyProperty));
end;

 ereditato (tramite la parola chiave *inherited*),
Infatti non ho mai capito perché questa cosa fosse possibile.  E'
logicamente errata, a mio avviso.  Tanto è vero che in altri linguaggi
(come il C++) evitare di chiamare il costruttore della classe madre è
impossibile, oltre a non esserci costruttori virtuali (il motivo della
cui presenza è, a mio avviso, ancora oscuro).

 cui presenza è, a mio avviso, ancora oscuro).
Su questo non sono d'accordo, o meglio trovo che la possibilità di 
definire costruttori differenti in grado di creare un'istanza della mia 
classe in modo diverso l'uno dall'altro sia comunque una feature 
interessante. Poi, c'è chi la utilizza di più o di meno...


 corretto:
No ovviamente, ma non era questo il caso dell'OP.
Ciao
-- 
Andrea Magni

 No ovviamente, ma non era questo il caso dell'OP.
Vedi sopra.

 cui presenza è, a mio avviso, ancora oscuro).
Senza costruttori virtuali come faresti una factory [un po' complessa, 
l'esempio banale di classi tutte con lo stesso costruttore lo 
tronchiamo a priori]?
-- 
Andrea Magni

 Vedi sopra.
Stai dicendo che il problema dell'OP si risolve inserendo quella 
chiamata a inherited?
-- 
Andrea Magni

 interessante.
Ma il C++, pur non implementando direttamente i costruttori virtuali,
consente di fare questa operazione mediante un normale metodo virtuale
e la covarianza sul tipo di ritorno.

> Senza costruttori virtuali come faresti una factory [...]
L'implementazione di una factory (anche complessa) non dipende
necessariamente dalla presenza di costruttori virtuali, lo fai
benissimo anche in C++, che non ha costruttori virtuali.

 chiamata a inherited?
Non necessariamente, nei thread si aprono spesso dei "percorsi" di
discussione collaterali, in cui fa sempre bene tirare fuori i
"fondamentali", tanto per rinfrescare le idee.

 benissimo anche in C++, che non ha costruttori virtuali.
Allora attendo un esempio funzionante, in Delphi, di una factory di 
classi con costruttori diversi e senza uso di virtual...
-- 
Andrea Magni

 classi con costruttori diversi e senza uso di virtual...
Andrea, cerca di calmarti, hai preso questo thread di punta (come
tutti quelli in cui è coinvolta la mia persona, evidentemente).
Probabilmente da quello che ho scritto è sembrato che io ce l'avessi
con i costruttori virtuali, nello specifico (che in Delphi sono
sicuramente necessari per scrivere una factory come quella di cui
parli[1]), ma è il modello ad oggetti di Delphi in generale che non mi
piace.
[1] oltretutto, è un pò ridicolo persino dirlo, difficilmente qualcuno
potrà proporre soluzioni alternative, se le ipotesi di partenza sono
quelle che, per come è strutturato il linguaggio, prevedono
necessariamente la presenza di un costruttore virtuale.

 cui presenza è, a mio avviso, ancora oscuro).
Ora, se io non parlo arabo, la "presenza" di cui parli è riferita al 
fatto che in Delphi ci sono e la frase "il motivo è ancora oscuro" va 
presa come "Il motivo della presenza in Delphi dei costruttori 
virtuali è ancora oscuro".
Io ti ho fatto un esempio (che per esempio si applica benissimo alla 
creazione delle form partendo dalle classi registrate dal sistema di 
streaming) dove "il motivo della presenza dei costruttori virtuali in 
Delphi" non è così oscuro...
Non mi sembra di aver fatto polemica in nessun punto.
-- 
Andrea Magni

Andrea Laforgia wrote:
 > Andrea, cerca di calmarti, hai preso questo thread di punta (come
 > tutti quelli in cui è coinvolta la mia persona, evidentemente).
Non mi sembra...
Cmq, citando un tuo messaggio:
 >  Tanto è vero che in altri linguaggi
 > (come il C++) evitare di chiamare il costruttore della classe madre è
 > impossibile, oltre a non esserci costruttori virtuali (il motivo della
 > cui presenza è, a mio avviso, ancora oscuro).
Ora, se io non parlo arabo, la "presenza" di cui parli è riferita al 


 e la covarianza sul tipo di ritorno.
Non ho ben capito cosa intendi, forse perchè non conosco il C++.
Se mi scrivi un esempio (quando hai tempo), forse mi chiarisco le idee e 
imparo qualcosa di nuovo a riguardo. ;-)


 Delphi 8 più corretta perchè elimina qualsiasi ambiguità.
Io ho sempre messo "inherited" anche se erano discendenti diretti di
TObject o TPersistent, non si può mai sapere nella vita... magari in D9
potranno mettere altra roba in quei costruttori ed allora diverrà
indispensabile averne l'eredità.
Ciao,
Andrea

 Non mi sembra di aver fatto polemica in nessun punto.
Coda di paglia ? ;-)

 indispensabile averne l'eredità.
Fai bene.  Oltretutto non ho capito perché bisogna obbligare i
programmatori e mettere sempre quell'istruzione e non possa invece
implicitamente inserircela il compilatore, durante la traduzione del
codice.

 codice.
Mah, questo no, non mi piacerebbe.
Personalmente, non apprezzo compilatori invasivi che
modificano il corso - magari voluto - del mio codice.
Onestamente non mi viene in mente un buon motivo in
base al quale non bisogna chiamare inherited nel
costruttore del codice, ciò però non toglie che
talvolta potrebbe servire, anche se non mi è mai
capitata la necessità.
Ciao,
Andrea

 capitata la necessità.
No, "inherited" bisogna usarlo *sempre*.

 codice.
A me è capitato, all'interno di un metodo "costruttore", di dover 
richiamare il metodo costruttore ereditato DOPO l'esecuzione di alcune 
istruzioni, quindi non all'inizio del metodo stesso.
La stessa cosa vale per il metodo "distruttore", nel quale voglio sempre 
avere la possibilità di richiamare il metodo ereditato quando e come 
voglio, nel rispetto comunque delle regole che governano, nel caso di 
Delphi, le classi della VCL.
Secondo me, la "forzatura" introdotta in Delphi 8 è la soluzione 
migliore nella quale si fa obbligo di richiamare il costruttore.


 istruzioni, quindi non all'inizio del metodo stesso.
Ma questo non è normale, a mio avviso.  In una normale gerarchia di
classi, il costruttore della classe madre *DEVE* essere chiamato come
prima istruzione.  Citami il caso specifico, magari...

 prima istruzione.  Citami il caso specifico, magari...
Non è normale fino a quando non viene consentito... :-)
La VCL include costruttori che eseguono codice prima e dopo la chiamata 
al metodo costruttore ereditato: guarda l'implementazione di 
TCustomForm.Create.
Inoltre, considerando che una classe può avere metodi costruttori 
differenti, potrei avere la necessità di inserire all'interno di un 
ulteriore costruttore una "chiamata selettiva" ad altri costruttori, 
magari ispezionando con un'istruzione *if* i parametri passati e 
chiamando un metodo costruttore piuttosto che un altro.
Nel caso specifico di cui parlavo, ho a che fare con un componente che 
deve verificare la classe di appartenenza del proprio Owner; se la 
classe non è quella corretta, viene generata un'eccezione impedendo, di 
fatto, la creazione del componente stesso.
Non mi vengono in mente altri esempi, ma questo non vuol dire che non ve 
ne siano più. :-)


 fatto, la creazione del componente stesso.
Anche questo non mi sembra molto corretto (il fatto, poi, di sollevare
eccezioni durante la costruzione di una classe mi fa venire i
brividi).  Se hai definito il costruttore della tua classe con un
Owner di un certo tipo, stai implicitamente accettando il fatto che
qualsiasi Owner di quel tipo vada bene.  Limitare poi, a run-time, il
range di Owner consentiti, mi sembra una tecnica molto poco pulita.

 generale di una OOP corretta.
Aooo hai rotto se delphi non te piace torna a lavorà con il C++!!
Il C++ è più fico il C++ è più bello il C++ è più simpatico.
Cammina.....  ora vado sul tuo pc e disinstallo delphi.
:)
ciao
   gabriele

 Cammina.....  ora vado sul tuo pc e disinstallo delphi.
PROVACI ! PROVACI ! (a venire alla scrivania, non a disinstallare
Delphi che non me ne frega niente ehehhehe)...

 generale di una OOP corretta.
Ovvio che non è detto sia normale, ad ogni modo non sono mai stato 
informato, né ho letto da qualche parte che il costruttore della classe 
derivata debba necessariamente essere il primo metodo ad essere 
richiamato. :-|


 richiamato. :-|
?!
Semmai della classe "base", non di quella derivata.

 Semmai della classe "base", non di quella derivata.
Sorry...ho sbagliato a scrivere.


> Sorry...ho sbagliato a scrivere.
Ad ogni modo ne ho già parlato nei messaggi precedenti del thread...

Semmai della classe "base", non di quella derivata.
a questo punto, devo dedurre che qualcuno si e' "confuso" cammin facendo ;-)
(che potrei essere io stesso ;-))
-- 
Morde. (
mo...@despammed.com
)
M-List di icld: 
http://it.groups.yahoo.com/group/icld/
Firefox, il miglior browser: 
http://www.gxware.org/mozilla/

 Ad ogni modo ne ho già parlato nei messaggi precedenti del thread...
Comprendo, ma non la vedo allo stesso modo.
In qualsiasi documentazione riguardo la programmazione ad oggetti che ho 
letto recentemente e in passato, ho sempre trovato esplicitata la 
condizione che la chiamata al metodo costruttore della classe base debba 
avvenire *prima* di utilizzare risorse fornite dalla classe base 
stessa", ma non ho mai trovato alcuna forzatura o "pressione 
psicologica" sul fatto che la chiamata al metodo costruttore debba 
avvenire necessariamente *per prima*, tant'è che vi sono casi in cui 
torna utile, senza creare - tra l'altro - controindicazioni o effetti 
collaterali.
Il fatto che la VCL, quindi Delphi, fornisca questa funzionalità la 
trovo "una cosa in più", fermo restando che è responsabilità del 
programmatore sapere se e come utilizzarla.
Poi, dal mio punto di vista tecnico, il costruttore - salvo il fatto che 
crea un'istanza della classe - è sostanzialmente un metodo come tutti 
gli altri, pertanto trovo interessante il fatto di poterlo definire 
virtuale, di poterlo richiamare a piacimento nel punto che ritengo più 
giusto, pur avendo coscienza di ciò che sto realmente facendo, ma si 
tratta di una coscienza che il programmatore dovrebbe sempre avere... :-)


 a questo punto, devo dedurre che qualcuno si e' "confuso" cammin facendo ;-)
La soluzione verrà pubblicata su "La Settimana Enigmistica" nel "Quesito 
della Susi"... ;-) :-D


 prima istruzione.  Citami il caso specifico, magari...
Ciao,
a me capita sempre quando uso il TThread. Devo inizializzare le mie
variabili e fare alcune operazioni prima di richiamare il costruttore padre
che fa partire il thread.
Anzi, Inherited è proprio l'ultima istruzione del mio costruttore.
C'è da dire che per abitudine, anche se eredito da TObject, inserisco sempre
l'inherited all'inizio.
Come Marco, non mi piacerebbe che il compilatore aggiungesse quello che io
non ho scritto, anche se obbligatorio... preferisco un messaggio di errore
che mi avverta di aggiungere quello che ho dimenticato.
Ciao
Giuseppe

 che fa partire il thread.
Immagino tu segua questo metodo quando il parametro CreateSuspended vale 
False. :-)
