Newsgroup: it.comp.lang.c++
Titolo: virtual destructor

Dato che ho qualche dubbio, qualcuno di voi ben istruito può spiegarmi
la differenza tra un destructor virtual ed uno normale; secondo voi,
quali sono i casi in cui sia meglio utilizzare la clausola virtual?
Grazie
-- 
Fabrizio Di Giuseppe
fabrizio.KILLME.@iride.com
(remove ".KILLME." from the address to send me a message)

quali sono i casi in cui sia meglio utilizzare la clausola virtual?
In pratica: se la tua classe Base ha una qualsiasi altra
funzione virtual, e quindi e` "fatta per essere derivata",
definisci virtual anche il suo dtor -- non ti costa praticamente
niente e ti mette al sicuro da possibili incidenti assai oscuri.
Se Base non ha nessuna funzione virtual, normalmente
questo e` segno che non e` "fatta per essere derivata",
e d'altra parte in questo caso fare un dtor virtual ha un
costo misurabile (tipicamente 4 byte circa per oggetto
di classe Base -- il puntatore a vtable che occorre se il
dtor e` virtual e che altrimenti non occorrerebbe).  Quindi
di solito in questo caso puoi risparmiarti il virtual dtor -- se
non in rari casi in cui puoi sapere dal tuo design che Base
e` "fatta per essere derivata" e in particolare che l'idioma
"Base *p=new Derivata ... delete p", o equivalente, puo`
essere usato nel resto del codice.
Alex

 giusto dipende anche l'uso del giusto operator delete.
[...]
Scusa, ma non ti ho trovato molto chiaro. Comunque, ho fatto qualche
prova ed ho scoperto come funziona il meccanismo dei virtual dtor. Ecco
il codice che ho scritto per fare le prove:
	class Alfa {
		public:
						Alfa () {cout << "+Alfa\n";};
						~Alfa () {cout << "-Alfa\n";};
	};
	class AlfaDerivata: public Alfa {
		public:
						AlfaDerivata () {cout << "+AlfaDerivata\n";};
						~AlfaDerivata () {cout << "-AlfaDerivata\n";};
	};
	class Beta {
		public:
						Beta () {cout << "+Beta\n";};
			virtual		~Beta () {cout << "-Beta\n";};
	};
	class BetaDerivata: public Beta
	{
		public:
						BetaDerivata () {cout << "+BetaDerivata\n";};
			virtual		~BetaDerivata () {cout << "-BetaDerivata\n";};
	};
	int main() {
		Alfa* a = new AlfaDerivata ();
		delete a;
		Beta* b = new BetaDerivata ();
		delete b;
		AlfaDerivata* c = new AlfaDerivata ();
		delete c;
		return 0;
	}
Ed ecco il risultato stampato sulla console:
	+Alfa
	+AlfaDerivata
	-Alfa
	+Beta
	+BetaDerivata
	-BetaDerivata
	-Beta
	+Alfa
	+AlfaDerivata
	-AlfaDerivata
	-Alfa
In pratica, se non si include la clausola virtual, il distruttore
chiamato è quello della classe specificata nella definizione del
puntatore, viceversa virtual permette di chiamare comunque il
distruttore appropiato. Mi pare che un distruttore non virtual serva a
ben poca cosa.
Grazie lo stesso
Ciao.


Mi pare che un distruttore non virtual serva a ben poca cosa.
Serve a risparmiare 4 byte per ciascun oggetto di quella
classe (o altra da essa derivata), se essa non ha alcuna
altra funzione virtuale.  Ad esempio:
class Punto {
public:
    unsigned short x,y;
};
dovrebbe occupare 4 byte -- aggiungendovi un dtor
virtuale, dovrebbe occuparne 8, esattamente il doppio.
Alex

 altra funzione virtuale.
Opinione personale: ma questo risparmio è rischioso in fase di sviluppo.
Se estendo la classe ereditanto e per sbaglio dimentico di includere la
clausola virtual al dtor incorro in un bug che andrà rilevato e
corretto. Non è meglio procedere alla rimozione delle virtual inutili
quando la struttura delle classi si stabilizza?
Grazie dei suggerimenti.


quando la struttura delle classi si stabilizza?
Puoi anche decidere di segnare tutti i metodi
come virtual, si` -- in questo caso, pero`, penso
che potresti ottenere prestazioni equivalenti, e
molto piu` in fretta, programmando in Java (dove
l'ottimizzazione sara` di definire final i metodi,
dove in C++ toglieresti il virtual -- col vantaggio
che il compilatore ti avverte se hai segnato un
final a sproposito, cioe` per un metodo che in
realta` viene overridden piu` a valle).
In C++ (e in realta` anche in Java, ma e` meno
cruciale) e` meglio stendere un buon progetto di
architettura sin dall'inizio, e in uno schema del
genere quali classi siano polimorfiche (con dei
virtual e altre classi derivate) e quali no risulta
gia` chiaro -- e se nel corso di sviluppo la scelta
va cambiata, virtualizzare anche il distruttore e`
il minimo dei problemi.
Alex