Newsgroup: it.comp.lang.c++
Titolo: Non chiamare funzioni virtuali nel costruttore

Mi sembra di capire che nel costruttore di un oggetto non si possono 
chiamare funzioni virtuali. Il motivo è che si rischierebbe di chiamare 
una funzione della classe derivata quando la classe derivata non è 
ancora stata inizializzata. Stessa cosa dicasi per il distruttore.
Se questa regola è valida, come mai il compilatore non mi dà errore?!?!? 
Ci ho perso le ore per capire come mai si bloccava in runtime, e ci sono 
riuscito (credo) solo perché la funzione virtuale era pura.
E.

 riuscito (credo) solo perché la funzione virtuale era pura.
Puoi postare il codice? 

Non so se questo codice rispecchia il caso da te citato, ma in effetti non 
da errore di compilazione, ma a run time non appare niente, penso vada 
subito in crash.
Forse il compilatore non č in grado di capire che quelle istruzioni a 
runtime daranno errori.
#include <iostream>
class A {
      public :
             A();
      virtual void f() {
              std::cout << "A::f" << std::endl;
      };
};
class B : public A {
      public :
      virtual void f() {
              std::cout << "B::f" << std::endl;
      };
};
A::A() {
       A* a1 = new A();
       A* a2 = new B();
       B* b = new B();
       a1->f();
       a2->f();
       b->f();
};
int main() {
    A a;
} 

 subito in crash.
Dentro il costruttore di A cerchi di costruire un altro A? Forse va in loop.
EMG
--
EMAG Software Homepage:     
http://www.emagsoftware.it
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg
The EMG Music page:         
http://www.emagsoftware.it/emgmusic
 

 loop.
Puo darsi, ma il programma si chiude immediatamente, non mi pare un loop. 

 Puo darsi, ma il programma si chiude immediatamente, 
in debug o al run ?
Naturalmente si capiva, imho, che per loop avesse inteso 
dire "ricorsione infinita", non certo un ciclo. Indi 
significa che vai a finire in uno stack overflow, se una 
procedura chiama sé stessa senza condizioni di uscita.
In ogni caso anche se debugghi facendo step-out dal 
costruttore, dovresti crashare subito in tempo nullo.
Non so ... prova a eseguire passo passo e tracciare i valori 
dello stack pointer dentro al costruttore, per vedere se il 
problema è quello
ciao
Soviet


 infinita", non certo un ciclo.
Ovviamente.


infinita",
Si, eheh, ma pensavo che in ogni caso richiedesse un po di tempo 
l'allocazione ricorsiva di memoria fino a raggiungere lo stack overflow. 

 riuscito (credo) solo perché la funzione virtuale era pura.
Dunque ho fatto qualche esperimento. Mi pare di capire che sia possibile 
chiamare funzioni virtuali dal costruttore. Quello che dovrebbe 
succedere è che finchè non è stato creato l'intero oggetto, la funzione 
virtuale chiamata è quella dell'oggetto già costruito. La cosa è in 
effetti sensata. Il problema c'è quando una funzione è astratta. In tal 
caso può succedere che il compilatore non si accorga della cosa, come 
nell'esempio seguente. In queste situazioni probabilmente succede che 
venga fatta una chiamata all'indirizzo 0.
#include <iostream>
using namespace std;
class A {
public:
   virtual void f()=0;
   void g() {
	f();
   }
   A() {
     cout<<"here is A::A"<<endl;
     g();
   }
};
class B
   : public A
{
public:
   virtual void f() {
     cout<<"here is B::f"<<endl;
   }
};
int main()
{
   B b;
   b.f();
   return 0;
}

A me dice:
here is A::A
pure virtual method called
e poi va in crash 

 Dunque ho fatto qualche esperimento.
Anziché fare esperimenti, potevi aspettare che io tornassi dalla
montagna. :)
Nel costruttore e nel distruttore le chiamate a funzioni virtuali vengono
risolte come se fossero funzioni membro ordinarie. Più precisamente,
dovremmo dire che durante l'esecuzione del costruttore o del distruttore
l'oggetto è trattato a tutti gli effetti come se fosse esattamente di quel
tipo. Questo non vale solo per le chiamate virtuali, ma anche per tutte le
operazioni legate all'RTI.
Se si cerca di invocare una funzione virtuale pura, il comportamento è
indefinito.
Max

 risolte come se fossero funzioni membro ordinarie.
Ah ok. Ma mi pare sia proprio la stessa cosa che dicevo io! In pratica 
durante la costruzione il puntatore alla vtable viene modificato man 
mano che la classe viene costruita...
E.

 chiamare funzioni virtuali dal costruttore.
Si. No. Ma non farlo. In primo luogo puoi chiamare funzioni virtuali che
però non sono trattate come virtuali.
Ovvero nel costruttore di A l'unico oggetto al mondo è A e pertanto
viene chiamata A::f. Sempre. Quindiè come se non fossero virtuali.
Se le hai rese virtuali, avrai avuto un buon motivo. Per cui sappi che
li la loro "virtualità" è inficiata. 
In definitiva il consiglio generale è "non chiamare funzioni virtuali da
costruttori e distruttori". Il programma è più prevedibile e amen.
-- 
-riko