Newsgroup: it.comp.lang.c++
Titolo: costruttori e distruttori

ciao sono un neofita del C++ e lo sto studiando sul libro del Lippman, terza
edizione.
Volevo porvi la seguente domanda:
Se non ho capito male, quando creo una classe derivata viene richiamato
prima il costruttore della classe base e poi quello della derivata,
giusto???
Poi quando la distruggo e' vero che viene richiamato prima il distruttore
della classe derivata e poi quello della base???
Un'altra domanda, ho visto sul libro che e' possibile per una classe
derivare piu' classi, es:
class a: public b, public c...
in questo caso l'ordine che viene seguito e' quello dell'ordine con cui
vengono richiamate le classi basi, ovvero prima quello di b e poi quello di
c????
e poi l'ordine inverso viene richiamato per i ditruttori???
scusate le domande banali, ma ho iniziato a studiarlo da poco...
ciao e grazie in anticipo

 e poi l'ordine inverso viene richiamato per i ditruttori???
Questo non sono sicuro, e non avendo lo standard sotto mano non posso 
dirtelo con certezza. Ma in fondo, se scrivi il codice "bene" non dovrebbe 
cambiarti niente. :-) Ciao.
-- 
Andrea Bergia - studente          Linux Registred User #281550
Per favore non mandatemi allegati in Word o PowerPoint.
Si veda 
http://www.fsf.org/philosophy/no-word-attachments.html

 ciao e grazie in anticipo
Ciao!

 Sě, corretto.
Si č corretto perň vorrei completare con un esempio, dato che all'epoca mi
ero imbattuto in problemi di questo tipo...
Nel codice seguente ad esempio...
// prova dei distruttori
#include <iostream>
using namespace std;
class classe_a {
        public:
        classe_a(int x) {
                cout << "costruisco a" << endl;
                p=x;
        }
        ~classe_a() {
                cout << "distruggo a" << endl;
        }
        private:
        int p;
};
class classe_b : public classe_a {
        public:
        classe_b(int x) : classe_a(x) {
                cout << "costruisco b" << endl;
        }
        ~classe_b() {
                cout << "distruggo b" << endl;
        }
};
int main() {
        cout << "prova classe a" << endl;
        classe_a* a;
        a=new classe_a(0);
        delete a;
        cout << "prova classe b" << endl;
        classe_a* b;
        b=new classe_b(0);
        delete b;
        system("pause");
        return 0;
}
quando viene costruita l'istanza b, se l'avessi scritta come classe_b* b non
ci sarebbero stati problemi ma nel caso del listato, bisogna stare attenti a
come vengono chiamati i distruttori.
In questo caso quando viene creata b, viene invocato il costruttore di a,
poi il costruttore di b.
Quando l'istanza viene chiusa, allora viene invocato il distruttore di a, e
non quello di b.
Per chiudere l'istanza correttamente č necessario definire il distruttore
della classe a come virtual.
        virtual ~classe_a() {
                cout << "distruggo a" << endl;
        }
Scusatemi se mi sono dilungato, ma penso che sia un caso di fondamentale
importanza per chi desidera imparare il C++.
Paolo Ferraresi.

 distruttore della classe derivata e poi quello della base???
Giusto, ma con riserva.
Nel caso in cui venga chiamato la delete per la classe padre, anche se 
l'istanza è della classe figlio il distruttore figlio viene chiamato solo se 
il distruttore padre è dichiarato virtual.
-- 
---
In silenzio anche un idiota sembra intelligente. Ma non c'è problema,
l'idiota vuol sempre dire la sua.

 distruttore della classe a come virtual.
Giusto quello che suggerisci, ma non il comportamento che descrivi.
O meglio, si tratta del comportamento che esibisce il tuo compilatore in
quella determinata situazione.
E' stato scritto tante volte, ma visto che l'OP è alle prime armi è bene
ribadirlo.
Il comportamento previsto dallo Standard in quella situazione è
semplicemente indefinito. Non è detto, cioè, che il problema si esaurisca
semplicemnte nella mancata chiamata al distruttore della classe derivata.
(Non so che compilatori usi, ma con il GCC è facile creare una situazione 
in cui la chiamata a delete produce un "segmentation fault" se la il dtor
della classe base non è virtuale.)
Max

Paolo Ferraresi.
Lo standard dice che se viene chiamato delete su un puntatore
in cui il tipo effettivo puntato non corrisponde al tipo
del puntatore e la classe non ha un distruttore virtuale
gli effetti sono imprevedibili (tanto imprevedibili quanto
andare a scrivere fuori da un array, per intenderci).
Ci tengo a sottolinearlo perche' capita spesso di trovare
gente che dice che invece che quello che accade e' che
viene semplicemente chiamato il distruttore della classe padre. 
Forse questo e' quello che accade con qualche compilatore
(anzi, probabilmente con la maggioranza dei compilatori) ma
non e' qualcosa su cui fare affidamento.
HTH
Andrea

         }
Scrivi
           classe_a(int x) : p(x) { ... };
Almeno ti assicuri che i membri dato siano costruiti direttamente con i 
valori corretti invece che costruiti e riassegnati, e che questi valori 
siano gia' disponibili quando entri nel corpo vero e proprio del 
costruttore.
Ciao,
Nicola

 scusate le domande banali, ma ho iniziato a studiarlo da poco...
Eddeche? Almeno ti chiarisci per bene i concetti fondamentali.
Ciao,
Nicola

E' proprio questo il problema che si verifica nel mio codice:
ho creato una classe a e una derivata b
scusate la sintassi se e' approssimativa, ma sto scrivendo a memoria, dato
che ho il listato al lavoro
e scusate i caratteri grandi, ma ultimamente ho problemi nel vedere bene a
fuoco
classe a
{
    public:
        a(const char* ptszPorta);
        virtual ~a();
    protected:
        char *ptMiaPorta;
}
nel costruttore di a
a::a(const char* ptszPorta)
{
    // ho omesso i controlli su un puntatore nullo e sulla memoria
disponibile
    ptMiaPorta = new char[strlen(ptszPorta) + 1];
    strcpy(ptMiaPorta, ptszPorta);
}
a::~a()
{
    if(ptMiaPorta)
        delete [] ptMiaPorta;
}
class b : public a
{
    public:
    b(const char* ptPorta);
    ~b();
}
costruttore di b:
b::b(const char* ptPorta) : a(ptPorta)
{
    // utilizzo il costruttore di a per copiare dentro ptMiaPorta il nome di
un nuovo
    // file da aprire, e' giusto???
    // cosi' ptPorta subisce lo stesso trattamento di ptMiaPorta, giusto???
}
b::~b()
{
}
ora quando vado con il debug, sebbene abbia dichiarato il costruttore di a
come virtual
l'ordine avviene nel seguente modo:
costruttore di a
costruttore di b
distruttore di a
distruttore di b
sono agli inizi e non capisco dove sto sbagliando...
ciao e grazie in anticipo...





Ciao,
Nicola
Me los pieghi in due parole che significa
classe_a(int x) : p(x) { ... };
ciao

 classe_a(int x) : p(x) { ... };
ehm... era appunto quello che spiegava Nicola Musatti
nel suo post...
Comunque ci riprovo io:
class tua_classe
{
    int intero;
    public:
    tua_classe(int x):intero(x){};
    // tua_classe(int x){ intero=x }
}
Che deve fare il costruttore?
Deve inizializzare gli oggetti membro della classe,
in questo caso 'intero'.
Entrambi i costruttori lo fanno, ma quello commentato
prima crea 'intero' con valore indefinito, poi, nel corpo
del costruttore, prende il valore 'x' passatogli e lo
assegna ad 'intero'
Il costruttore non commentato, invece, crea 'intero' già
di valore 'x' e poi entra nel corpo del costruttore
(che nel caso non fa nulla).
--
Gerolamo