Newsgroup: it.comp.lang.c++
Titolo: distruttori virtuali

C'è qualcuno che mi può spiegare cosa avviene in dettaglio (e perchè) se
richiamo funzioni virtuali in un distruttore ?
E in un distruttore virtuale ?
A quello che ho capito :
class base1
{
    ...
    virtual void distruggi(void);
    ~base1() {distruggi();}    // chiama comunque base1::distruggi()
    ...
};
class base2
{
    ...
    virtual void distruggi(void);
    virtual ~base2() {distruggi();} // chiama eventualmente
derivata::distruggi()
    ...
};
Non ho ben capito cosa suggede se il distruttore è virtuale, ma non lo è
distruggi().
--
*** SPARTACO ***
-> 
amu...@tin.it
 <-
http://www.pegacity.it/informatica/case/473/index.htm

distruggi().
La chiamata di funzioni non virtuali (sia da dentro un dtor, sia in
qualsiasi altro caso) non da` fortunatamente adito a nessuna
difficolta`.
Queste problematiche sono ben sviscerate nel testo del Lippman
"Inside the C++ Object Model" (da non confondersi col suo noto
tutorial).
Alex

>>Nel corso della normale esecuzione di un distruttore, le classi piu`
derivate sono gia` state distrutte quando si arriva a distruggere una
classe base.  Quindi, pensa che caos se il distruttore della classe
base, chiamando una propria funzione virtuale, si trovasse ad
eseguirne l'override in una classe derivata... gia` totalmente
distrutta e ridotta ad un cumulo di macerie...!  Ergo, in un dtor
come in un ctor (per ragioni duali ma identiche), la funzione
virtuale viene "de-virtualizzata", nel senso che, chiamandola, si
ottiene la versione definita nella classe corrente (o sua antenata),
MAI eventuali override fatti da classe piu` derivate.<<
Magnifico : ora è veramente chiaro.
Ora però mi pongo un altro problema :
se io volessi far chiamare da i distruttori della mia ipotetica gerarchia
delle funzioni virtuali, cosa potrei scrivere ?
Se scrivo
class base
{
    ...
    virtual void distruggi();
    virtual ~base() {distruggi();}
    ...
};
class derivata : public base
{
    ...
    virtual void distruggi();
    virtual ~derivata() {distruggi();}
    ...
};
base *p = new derivata();
...
delete p;
Vengono chiamati prima derivata::distruggi() e poi base::distruggi() !
La cosa non mi va per niente, perchè vorrei poter scrivere p->distruggi().
Mi devo rassegnare ad avere la funzione distruggi che chiama quella della
base e a mettere del codice nel distruttore che distrugga solo al suo
livello ?


livello ?
Puo farlo in vari modi.  Se sai che gli oggetti in questione vivono sempre
sull'heap, puo` essere la stessa distruggi() a fare delete this dopo avere
fatto il resto del proprio lavoro distruttivo, ad esempio.
Se vuoi che una sola distruggi() venga eseguita, metti un flag nell'oggetto
base, resettalo dalla derivata::distruggi, testalo in base::distruggi.
Ma seriamente, cosa vorresti con questo codice -- che fosse eseguita
due volte la derivata::distruggi, la seconda dopo che sono gia` stati
zappati via tutti i campi che la derivata aggiunge alla base?!  Sul serio,
i tuoi desiderata non mi sono affatto chiari.
Alex

>> Ma seriamente, cosa vorresti con questo codice -- che fosse eseguita
due volte la derivata::distruggi, la seconda dopo che sono gia` stati
zappati via tutti i campi che la derivata aggiunge alla base?!  Sul serio,
i tuoi desiderata non mi sono affatto chiari. <<
Non ho pensieri così contorti, volevo solo essere sicuro di aver esplorato
tutte le possibilità.
Comunque il mio problema vero è che voglio poter chiamare una bella (e
lunghetta) funzione virtuale che cancella dalla memoria una lista (diciamo
così), per 'resettare' il mio oggetto. La derivata::distruggi() chiama
base::distruggi() e in questo caso, mi va benissimo. Ovviamente se la
chiamata la metto nel distruttore di derivata, e in quello di base ho il
risultato di richiamare 1 volta derivata::distruggi() e 2 volte
base::distruggi().
(base non è astratta e devo poterla creare e distruggere).
Comunque l'idea più semplice è quella del flag.
Grazie.
