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

Una domanda sulle classi virtual e sulle loro classi derivate.
Una classe B child di una classe virtuale pura A deve avere
obbligatoriamente il distruttore dichiarato virtual o no ?
Vi faccio questa domanda perché ho avuto una discussione con una mia
collega che utilizzava una classe child di una classe virtual e che
implementava, tra le altre cose, apertura e chiusura di file, e che
nell'implementazione del distruttore richiama semplicemente la close
di un fstream.
Il distruttore stesso, però, non era dichiarato virtual.
In compilazione tutto ok, ma in esecuzione dava un core dump proprio
sulla close.
Lei non ha fatto altro che togliere la close dovunque comparisse nel
codice ed ha risolto il problema.
Io le ho detto che bastava semplicemente dichiarare virtual il
distruttore ed il problema era risolto in maniera rapida ed efficace,
ma mi sono sentito dare quasi dell'ignorante.
Secondo voi chi ha ragione?
Grazie per l'eventuale contributo
Francesco

 Secondo voi chi ha ragione?
Credo che più che ragione o torto bisogna ricercare l'errore!
Ciao,
j0k3r

 ma mi sono sentito dare quasi dell'ignorante.
Non è stato per niente carino da parte sua essere scortese
nella risposta. A parte questo, close tolta o metodo virtual
il problema è risolto ugualmente, non so però cosa succederà
la prossima volta che proverà a derivare un'altra classe child
da quella virtuale che ha ora. Così senza sapere non mi sento
di dare giudizi su quale sia la soluzione migliore, potrebbe
anche darsi che quella close, lì, non avesse proprio motivo
di starci. Però una classe virtuale senza distruttore virtuale
non mi pare una buona idea, in ogni caso. Mah

 codice ed ha risolto il problema.
Invocare 'close' su un'oggetto fstream non può avere comportamento indefinito.
Se, togliendo la chiamata a 'close', il problema svanisce "misteriosamente", può
darsi che abbiate soltanto mascherato un sintomo, senza identificare l'errore.
Max

 obbligatoriamente il distruttore dichiarato virtual o no ?
Il distruttore *deve* essere dichiarato virtual ed implementato (anche
se virtuale puro) nella classe base; se e' virtuale nella classe base
lo e' automaticamente anche nelle classi derivate, quindi e'
sufficiente quello sintetizzato dal compilatore.
Ciao,
Nicola

 se virtuale puro) nella classe base; 
Ciao, questo non lo sapevo, in pratica il distruttore e' l'unico metodo 
che può essere definito anche se virtuale puro ? Come mai questa 
'differenziazione' del costruttore rispetto ai metodi normali ?
Grazie,
j0k3r

 ....del costruttore rispetto ai ... 
Ovviamente intendevo distruttore....

 'differenziazione' del distruttore rispetto ai metodi normali ?
I distruttori delle classi base vengono chiamati automaticamente in cascata
dopo il distruttore della classe derivata, quindi e' importante che esista
ugualmente l'implementazione del distruttore, anche se dichiarato astratto.
Il fatto che si possa definire un distruttore come astratto (nonostante
debba essere comunque implementato) e' un caso un po' estremo...
Qualcuno mi corregga se sbaglio, pero' credo che l'unica ragione per cui e'
consentito farlo e' che questo permette di rendere una classe astratta,
quindi non istanziabile, anche se non possiede nessun metodo virtuale
puro...
...sul fatto poi che questo sia effettivamente utile, se ne potrebbe
discutere, ma mi piace pensare che in C++ ci siano tante cose che possono
diventare utili anche se non e' immediato vedere dove :-)

...

No, tutte le funzioni membro virtuali pure possono essere definite,
solo non e' possibile farlo all'interno della dichiarazione della
classe:
class C {
  public:
    virtual int f() = 0;
};
int C::f() { return 42; }
Il problema e' che questa funzione puo' essere solo chiamata in modo
esplicito:
C::f();
La sua definizione ha qualche senso solo se si adotta una qualche
convenzione particolare (ad es. tutte le funzioni derivate *devono*
chiamarla per prima cosa), ma si tratta in ogni caso di una scelta
debole, perche' non verificata dal compilatore.
Il caso del distruttore virtuale puro e' diverso, perche' viene
comunque chiamato durante la distruzione delle classi derivate.
Ciao,
Nicola