Newsgroup: it.comp.lang.c++
Titolo: Un costruttore può chiamare un metodo?

Salve a tutti.
Volevo chiedervi se un costruttore può chiamare un metodo della stessa
classe.
Vediamo un esempio:
class A{
            int dimensione;
            double istante_di_arrivo;
            int lista_abilitata;
            /....../
            public:
            list<Mio_oggetto> lista_obj;
            A(int size);
            A(int size,int elemento_1);
            A(int size,int elemento_1,int elemento_2);
            void Crea_lista(int numero_elementi);
            /...../
           };
Siccome ho dichiarato dei costruttori appartenenti ad una classe di
overloading, per evitare di riscrivere praticamente quasi tutto uguale per i
due costruttori A(int,int) ed A(int,int,int)  ---almeno, per come li ho
pensati, un costruttore deve inserire solo elemento_1 all'interno della
lista "lista_obj" mentre l'altro deve inserire sia elemento_1 che
elemento_2, ma per il resto tutto è uguale--- avevo pensato di fare una cosa
del genere:
1) Definire una funzione membro della classe A che contenesse le operazioni
comuni ai costruttori 2 e 3 della classe di overloading,
2) In A(int ,int) fare una cosa del genere
         A:: A(int size,int elemento_1){
                            A a(SIZE); // Cosi ho chiamato un costruttore
                             int num_elementi=1;
                             Metodo_codice_comune(num_elementi);
                             }
3) In A(int,int,int) invece
       A:: A(int size,int elemento_1,elemento_2){
                            A a(SIZE); // Cosi ho chiamato un costruttore
                             int num_elementi=2;
                             Metodo_codice_comune(num_elementi);
                             }
Questa cosa può funzionare?
Cioè, può funzionare inviare un messaggio( chiamare un metodo) ad una
istanza di una classe quando ancora il costruttore non si è chiuso?
Grazie, al solito,
per la vostra disponibilità,
Sebastiano

Si, funziona. Ovviamente devi fare attenzione al fatto che proprio
perche' il costruttore non e' terminato, non puoi far conto sulla
situazione "pulita" che avresti al termine della costruzione.
In ogni caso all'interno del corpo del costruttore sei garantito che i
costruttori delle superclassi sono stati eseguiti, cosi' come quelli
degli oggetti che la tua classe contiene direttamente.
Ciao,
Nicola

 wrote in message 39A22B13...@divalsim.it...

A questo proposito approfitto per togliermi un dubbio.
All'interno del corpo di un costruttore si può fare riferimento a this?
Manlio Perillo

Certamente.
Ciao,
Nicola

Grazie,
davvero tanto.
Una domanda che non c'entra niente, o quasi. Ma come hai fatto a diventare
cosi in gamba, tu e d i tuoi colleghi del news ? Mi svelate "qualche
segreto"?
Anche io vorrei imparare a cavarmela un po.
Bye,
Sebastiano

Tieni conto che lavoro nell'informatica da quasi tredici anni, piu'
l'universita', per cui ci sarebbe piuttosto da preoccuparsi se non
avessi imparato niente :-)
Per il resto l'unica ricetta che ti posso suggerire e': leggi e metti in
pratica. Libri, riviste, documenti che trovi sul web, newsgroup,
cercando di fare attenzione alla qualita' di cio' che trovi in giro. Le
nostre FAQ, postate da poco, possono darti qualche suggerimento.
Ciao,
Nicola

                             }
Qui non ci sono problemi, chiamare metodi della stessa classe e'
lecito (basta che ovviamente si capisca cosa si sta facendo nel
senso che il metodo si trova un oggetto quasi-funzionante in cui
pero' non tutto il codice di costruzione e' stato completato).
Dopo l'INIZIO dell'esecuzione di un costruttore ci si trova in
un normale metodo che puo' fare qualunque elaborazione; con due
sole differenze:
  1) eventuali exception provocheranno sempre l'eliminazione
     dell'oggetto (senza chiamare il distruttore per la classe
     ma chiamando il distruttore per tutti i membri)
  2) chiamate di metodi virtuali prima che sia stato completato
     il costruttore della parte base un oggetto derivato non
     subiscono l'override verso i metodi dell'oggetto derivato.
     Esempio:
#include <iostream>
class Base
{
  public:
    Base()
    {
      std::cout << "Base::Base()\n";
      f();
    }
 
    virtual ~Base()
    {
      std::cout << "Base::~Base()\n";
      f();
    }
    virtual void f()
    {
      std::cout << "Base::f()\n";
    }
    void g()
    {
      std::cout << "Base::g()\n";
      f();
    }
};
class Derived : public Base
{
  public:
    Derived()
    {
      std::cout << "Derived::Derived()\n";
    }
 
    virtual ~Derived()
    {
      std::cout << "Derived::~Derived()\n";
    }
 
    void f()
    {
      std::cout << "Derived::f()\n";
    }
};
int main()
{
  Derived d;
  d.g();
}
In esecuzione si ottiene il seguente output:
Base::Base()
  // ok... siamo entrati nel costruttore di Base
Base::f()
  // Punto importante. Il costruttore di Base ha
  // chiamato f() che e' un metodo virtuale e,
  // anche se noi stiamo costruendo un oggetto
  // di tipo Derived, in questo momento la funzione
  // chiamata non tiene conto dell'override.
  // Questo oggetto non e' ancora un Derived!
Derived::Derived()
  // Finita la costruzione di base siamo entrati
  // nel costruttore di Derived. A questo punto
  // l'oggetto e' gia' un oggetto Derived completo
  // per quello che riguarda i meccanismi di
  // overriding dei metodi virtuali.
Base::g()
  // Qui siamo entrati nella funzione g() di Base
  // (chiamata dal main dopo la costruzione
  // dell'oggetto Derived)
Derived::f()
  // Come si vede ora chiamare f() in un metodo
  // di Base attiva il codice definito in Derived
  // (visto che si tratta di un metodo virtuale)
Derived::~Derived()
  // Finito il main si chiama il distruttore di
  // Derived per eliminare l'oggetto d.
Base::~Base()
  // Siamo entrati nel distruttore di base (chiamato
  // automaticamente dopo il completamento del
  // distruttore di Derived)
Base::f()
  // Punto importante. Anche in questo caso la
  // funzione chiamata con f() e' quella di Base
  // e non quella di Derived in quanto questo
  // oggetto in realta' non e' piu' un Derived
  // essendo gia' stata completata quella parte
  // di distruzione.
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

Ma allora, scusa, perchè mi è stato detto che funziona (mi riferisco a ciò
che mi ha gentilmente risposto Nicola Musatti) ?
Funziona soltanto il fatto di chiamare altri metodi prima che il costruttore
si chiuda?
Seguendo il tuo consiglio
anzichè fare:
A a(SIZE); // Cosi ho chiamato un costruttore
dovrei scrivere una funzione, praticamente identica al costruttore  A::
A(int size)
che viene chiamata da tutti i costruttori, anche da A:: A(int size), a
questo punto.
Per evitare ripetizioni farei allora cosi:
Funzione_elementi_comuni(int size)
{
/...../
}
1) A:: A(int size){
                        Funzione_elementi_comuni(int size);
                     }
2) A:: A(int size,int elemento_1){
                            Funzione_elementi_comuni(int size);
                             int num_elementi=1;
                             Metodo_codice_comune(num_elementi);
                             }
3) In A(int,int,int) invece
 A:: A(int size,int elemento_1,elemento_2){
                            Funzione_elementi_comuni(int size);
                             int num_elementi=2;
                             Metodo_codice_comune(num_elementi);
                             }
Che ve ne pare?
Bye,
Sebastiano.

questo punto.
Esatto. Questa e' la soluzione per codice condiviso
in piu' costruttori. Normalmente questa funzione
viene inoltre dichiarata "private" in modo che
nessun altro la possa chiamare esplicitamente.
Ha una certa diffusione anche lo scrivere solo il
costruttore di default che ritorna una specie di
oggetto "zombie" che viene in seguito inizializzato
sul serio con una chiamata specifica (o, come
vorresti fare tu) una chiamata a scelta fra N
possibili. Questo approccio, sebbene comodo in
alcuni contesti, *NON* e' un approccio
consigliabile per una serie di motivi (ad esempio
tutti i metodi dovrebbero controllare di non
essere stati chiamati per uno zombie).


Ho sbagliato io, non mi sono accorto che chiamavi un costruttore
esplicitamente. Per il resto la tua ultima soluzione mi sembra corretta.
sta a te valutare se la tua Funzione_elementi_comuni e' una funzione
libera oppure un altro metodo della classe.
Ciao,
Nicola

Grazie ancora a tutti voi,
Sebastiano.