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

Oggi mi sto facendo una cultura sulle funzioni virtuali e sui loro
parenti stretti distruttori virtuali, devo dire che fino ad adesso
non ero riuscito a capire a che servissero entrambi in quanto non
consideravo il caso dell'upcasting con relativo dynamic binding che
per quanto ne so e' il caso che richiede di usare un po' di keyword
virtual.
Comunque veniamo al dubbio: stavo leggendo Thinking in C++,a un certo
punto, anche se non la da come regola assoluta, Eckel dice che come
regola bisogna dichiarare virtuale un distruttore di una classe base
appena si definisce virtual una funzione della classe base stessa.
Tuttavia il programma che riporto sotto crea un memory leak, e la
soluzione del bug e' mettere come virtual il distruttore della classe
B2. Diciamo che in effetti da quanto ho capito non e' bene derivare
una classe concreta da un'altra concreta, ma insomma, esiste una regola
per sapere quando definire virtual i distruttori o comunque giusto
per stare tranquilli e' sempre meglio dichiararli cosi'?
class B2 {
public:
    B2() { cout << "B2::B2()" << endl; };
    ~B2() { cout << "B2::~B2()" << endl; };
};
class C2: public B2 {
public:
    C2() {
            cout << "C2::C2()" << endl;
            p = new char[10];
    };
    ~C2() {
            cout << "C2::~C2()" << endl;
            delete [] p;
    }
private:
    char *p;
};
main() {
        B2 *d = new C2;
        delete d;           // stampa B2::~B2()
}
Tra le altre cose, definire una classe base come astratta, oltre ad
esempio a prevenire l'object slicing "involontario" o meno nel passaggio
di parametri (o anche nelle assegnazioni?) e diciamo documentare una
progettazione piu' pulita, ha anche altri vantaggi?
-- 
Saluti,
 Francesco Cipriani

 progettazione piu' pulita, ha anche altri vantaggi?
"Evitare casini inenarrabili" e` un buon riassunto dei vantaggi: lo
slicing (in tanti casi), il problema della corretta implementazione
dell'assegnazione (in generale non risolubile), la duplicazione di dati,
il fortissimo coupling (dipendenza) di una classe da tutte le sue
classi-base (quest'ultimo e` la cosa peggiore per GROSSI progetti),
e la grossa riduzione di riusabilita` (polimorfica _e non_) che si ha
legando imprescindibilmente una "specifica di funzionalita` astratta"
(una pura interfaccia) ad una "concreta implementazione in un
particolar modo" di quella data funzionalita` astratta.
Parte dei problemi sono connessi all'eredita` multipla (e quindi non
toccano i linguaggi che ne mancano, come Smalltalk) e parte alla
classica verifica di correttezza dei tipi a compile-time (e quindi non
toccano i linguaggi che hanno altri approcci, come Object-CamL,
Smalltalk, Python, ...).  Ma, in C++, i problemi li hai proprio tutti...
Alex

 per stare tranquilli e' sempre meglio dichiararli cosi'?
La regola di Eckel è valida. Solo che il tuo caso era troppo semplice.
Se, come avviene nella pratica, ci fossero stati altri metodi nella
classe base, oltre ai soli c'tor e d'tor, alcuni di questi sarebbero
stati sicuramente virtuali. Comunque si può anche dire che il
distruttore dovrebbe essere posto virtuale quando la classe è pensata
per fungere da classe base, come evidentemente è nel tuo esempio.
EMG

progettazione piu' pulita, ha anche altri vantaggi?
Il vantaggio piu` evidente e` la separazione tra il codice della classe
che usa l'interfaccia e la classe che la implementa. Questo in generale
significa maggiore manutenibilita` e riusabilita` del codice, pensa ad
esempio al caso in cui sono possibili parecchie implementazioni
diverse dell'interfaccia (ad esempio per mappare dispositivi
hw diversi), l'uso di una interfaccia consente alle classi
utilizzatrici di comunicare con qualsiasi dispositivo in modo
pienamente trasparente.
Paolo
--------------------------------------------------
  Paolo Marotta
  Computer Science, University of Pisa
  home:   
http://www.cli.di.unipi.it/~marotta
--------------------------------------------------

 
Sbaglio o ocaml essendo un derivato di SML ha anche lui un
type-checking statico?
Ciao,
-- 
Diego    | Per le repliche elimina dal mio indirizzo le 
Dainese  | `x' e inverti le due parole intorno alla `@'

 type-checking statico?
Ha una _deduzione_ dei tipi associati alle variabili e non una
_dichiarazione_ idem idem -- per questo parlavo di "altri
approcci", genericamente, rispetto alla "classica verifica di
correttezza dei tipi" &cc, piuttosto che di "typing dinamico"
come si potrebbe dire per Smalltalk (e in un senso diverso
anche per Python).
Alex