Newsgroup: it.comp.lang.delphi
Titolo: Dubbio: Metodi Statici e Virtuali

Mi sapete per favore chiarire una cosa riguardo l'ereditarietà?
Supponiamo che io abbia una classe genitore con:
        a) un metodo statico;
        b) un metodo virtuale.
Poi, in una classe figlia, voglio:
    1) sostituire completamente il metodo della classe genitore;
    2) avere lo stesso identico metodo della classe genitore;
    3) avere un metodo con le stesse caratteristiche di base ma con
l'aggiunta
        di altro codice, per potenziare il metodo.
Io credo (è qui che vi chiedo aiuto per correggermi o confermare quanto
dico) che nella classe figlia la situazione sia la seguente:
CASO 1a:
è sufficiente dichiarare il metodo come se ciò non fosse stato fatto nella
classe genitore.
CASO 1b:
si DEVE fare l'override (usando stesso nome, stessi parametri ed eventuale
stesso tipo/i di ritorno).
CASO 2a:
non importa dichiarare nessun metodo; quando avverrà la chiamata del metodo
verrà usato quello della classe genitore.
CASO 2b:
si PUO' fare l'override, ma forse è meglio fare come in 2a
(qui il dubbio è che se si fa l'override poi il vecchio codice non verrà
usato, se non se ne fornisce uno noi)
CASO 3a:
non è possibile.
CASO 3b:
si può fare sia con INHERITED che con l'OVERRIDE
(forse è meglio inherited? Perché?)
In base ai dubbi che ho sui casi di sopra, ne sorgono altri due:
- che senso avrebbe fare l'override nel caso 2b (metodo identico a quello
della classe base, che è statico) ? Forse lo si deve fare solo se il metodo
nuovo ha lo stesso nome di quello "vecchio"?
- che senso avrebbe fare Inherited nel caso 2a (metodo identico a quello
della classe base, che è virtuale) ? Tanto vale non fare nulla.
Penso che chiarendo questi aspetti si faccia un gran favore non solo a me,
ma anche a tutti gli appassionati che si stanno avvicinando all'affascinante
mondo di Delphi!
Grazie a tutti!
Stefano


Innanzitutto, occorre precisare la differenza tra i metodi statici e i
metodi virtuali; è possibile "scavalcare" questi ultimi tramite la clausola
'override' poichè il loro indirizzo viene inserito all'interno di una
tabella, la VMT (Virtual Method Table). Ogni classe possiede una propria
VMT; all'interno della tabella vengono inseriti gli indirizzi dei metodi
virtuali "disponibili" per quella classe; per "disponibili" si intendono
tutti i metodi virtuali implementati in tale classe, inclusi quelli
appartenenti alle classi dalle quali discende. Quando si fa l'override di un
metodo virtuale ereditato all'interno di una classe, il suo indirizzo viene
inserito nella VMT al posto dell'indirizzo del metodo ereditato dalla classe
genitore. Quando si richiama un metodo virtuale dal codice, viene analizzata
la VMT della classe interessata ottenendo l'indirizzo assoluto del metodo
per poterlo eseguire; quando si inserisce 'inherited' nel codice di
implementazione di un metodo virtuale, non si fa altro che ripescare
l'indirizzo del metodo scavalcato all'interno della VMT della classe
genitrice ed eseguirlo, passando gli stessi valori dei parametri oppure
specificando parametri diversi.
Alcuni esempi di ciò che comporta questo aspetto:
1)
a meno che non sia dichiarato nella sezione 'private' della classe, un
metodo statico viene ereditato ed è accessibile alle classi discendenti;
tuttavia, non è possibile scavalcarlo tramite la clausola 'override' poichè
il suo indirizzo non viene inserito all'interno della VMT ma è statico,
appunto; è possibile dichiarare un metodo omonimo in una classe discendente:
si tratterà semplicemente di un nuovo metodo avente lo stesso nome e un
proprio indirizzo statico (non vi è nessuna relazione tra il nuovo metodo e
quello ereditato);
2)
aggiungendo un metodo virtuale X() ad una classe TGenitore, è possibile
scavalcarlo tramite la clausola 'override' in una ipotetica classe
discendente TFiglia; questo si traduce nella generazione di una VMT per la
classe TGenitore nella quale è presente l'indirizzo del metodo X; la tabella
di TGenitore viene duplicata per la classe TFiglia, ma l'indirizzo del
metodo X viene sostituito con il nuovo metodo di TFiglia. Si prenda in esame
questa istruzione:
  TGenitore(Obj).X;
Se Obj è di tipo TFiglia, viene eseguito il metodo X avente l'indirizzo
nella VMT di TFiglia; se l'implementazione di X in TFiglia contiene anche la
clausola 'inherited', viene eseguito il metodo ereditato X avente
l'indirizzo nella VMT di TGenitore. Se X fosse stato un metodo statico, il
metodo richiamato dall'istruzione sopra sarebbe quello implementato da
TGenitore; lo stesso effetto si sarebbe ottenuto se TGenitore.X fosse stato
virtuale e TFiglia.X statico; il metodo TFiglia.X infatti "nasconderebbe" il
metodo della classe base TGenitore.X (Delphi genera un warning in questo
caso).
Per eliminare il warning e informare Delphi che si intende volontariamente
sostituire il metodo virtuale ereditato con un metodo statico, occorre far
seguire la clausola 'reintroduce' alla dichiarazione del metodo X nella
classe TFiglia.
Ai metodi virtuali si affiancano inoltre i metodi dinamici (sono seguiti
dalla clausola 'dynamic'), i quali funzionano allo stesso modo per quanto
riguarda il meccanismo dell'ereditarietà, ma vengono gestiti in modo diverso
a livello di tabella degli indirizzi; la DMT (Dynamic Method Table) di una
classe contiene solamente gli indirizzi dei metodi dinamici dichiarati
all'interno di tale classe; gli indirizzi dei metodi ereditati non vengono
duplicati per la tabella ed è necessario risalire le DMT delle classi
genitore per individuare l'indirizzo del metodo da eseguire; questo
meccanismo consente di risparmiare memoria evitando la duplicazione degli
indirizzi (come avviene nella VMT), ma è più lento rispetto all'uso della
VMT.
Spero di non averti indotto troppa confusione dato che la mia chiarezza
espositiva non è troppo buona. :-)
Prova a fare qualche esperimento creando classi di esempio e richiamandone i
metodi variando le clausole e la natura dei metodi che le compongono...ti
può essere d'aiuto per capire i meccanismi dell'ereditarietà che sono quasi
più difficili da spiegare.
Ciao!
--
/\/\arco Breveglieri (
ma...@abls.it
)
· SINTESI S.r.l. (
www.sintesi.com
)
· ABLS Team (
www.abls.it
)

 espositiva non è troppo buona. :-)
No, anzi! Io ho capito benissimo!
Perfetto!! Ora ho le ideee decisamente più chiare!
Grazie ;-)
Stefano