Newsgroup: it.comp.lang.c++
Titolo: Semplice problema ereditarieta'

Ciao a tutti,
un problema semplice semplice. Perche' nel seguente codice ho un
errore di violazione runtime?
class Cibo {
private:
public:
	virtual void ingred() {cout << "Nessuno (o pure virtual)\n";}
};
class Pizza : public Cibo {
public:
//	Pizza() {pPomodoro = new int;}
//	~Pizza() {delete pPomodoro;}
	void ingred() {cout << "PomodoroMozzarella\n";}
private:
	int *pPomodoro;
};
void main()
{
	Cibo *pCibo = new Pizza[2];
	pCibo[1].ingred();
	delete[] pCibo;
}
Insomma, il polimorfismo non funziona. Credo che la soluzione stia nel
dichiarare un array di *puntatori* a Cibo, e inizializzarli (e
distruggerli) uno ad uno.
Si puo' dire che in questo caso il fatto di usare il puntatore come
array si sia "mangiato" la possibilita' di usare il polimorfismo?
In questo caso, "sentence" come
	Cibo *pCibo = new Pizza[2];
non dovrebbero essere vietate? A cosa possono servire?
Qualcuno potrebbe gentilmente farmi uno "schizzo" di cosa succede in
memoria?
Ho il sospetto che a runtime venga allocato spazio per oggetti di tipo
Cibo, che sono piu' piccoli, quindi quando chiamo il metodo vado a
leggere in una vtable che non c'e'... Mmmmhh...
C'e' un bel libro/tutorial (inglese o italiano) che fa capire cosa
succede in memoria in casi come questi? Ho lo Stroustrup, ma se non
sbaglio non spiega nemmeno cosa succede quando fai un new (il
compilatore scrive la dimensione dell'oggetto allocato all'inizio
della memoria puntata dal puntatore che viene ritornato da new).
Grazie mille!
Ciao, giulio
Please strip ".removeMe" to reply by email

 }
Spero di essere stato esauriente.
Porlock.

della memoria puntata dal puntatore che viene ritornato da new).
Non e' detto che la tua spiegazione sia necessariamente
quello che fa il compilatore. Alcune implementazioni usano
approcci diversi (ad esempio mantenere una hash table separata
con registrati i dati di housekeeping sui blocchi di memoria
allocati).
Quello che dice il linguaggio e' che array e polimorfismo non
vanno d'accordo, sia nell'accesso che nella chiamata di delete[].
Nota che anche i contenitori STL non sono polimorfici e quindi
quello che si usa quando e' richiesto polimorfismo sono
sempre contenitori di puntatori piu' o meno intelligenti o di
classi di tipo proxy.
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

 wrote:
| Ciao a tutti,
|
| un problema semplice semplice. Perche' nel seguente codice ho un
| errore di violazione runtime?
perche' usi i puntatori, e ti danni l'anima. Se non ne ai bisogno (e nel
99% del codice, non ne hai :-) usa std::vector. Al piu' sui puntatori, per
ultraottimizzare.
[...]
#include <vector>
[...]
| void main()
| {
| std::vector<Cibo> vectCibo;
  vectCibo.push_back(Pizza());
  vectCibo.push_back(Pizza());
| vectCibo[1].ingred();
| // delete[] pCibo; non serve! fa il vector!
| }
se poi vuoi i puntatori:
[...]
#include <vector>
[...]
void flush(std::vector<Cibo*> &vett){
    std::vector::iterator it;
    for (it = vett.begin(); it != vett.end(); ++it)
        delete (*it);
}
| void main()
| {
| std::vector<Cibo*> vect_pCibo;
  vect_pCibo.push_back(new Pizza());
  vect_pCibo.push_back(new Pizza());
| vect_pCibo[1].ingred();
  flush(p_vectCibo); /* svuota il vettore */
| }
Oppure derivi da std::vector e modifichi il distruttore.

 
Attenzione che così il polimorfismo fa a farsi benedire. vectCibo conterrà
comunque dei veri oggetti Cibo, sebbene il push_back accetti un Pizza&.
(Per inciso, se la classe Cibo è astratta, un vector<Cibo> non può nemmeno
esistere.)
Per avere quel tipo di interfaccia e preservare il polimorfismo si
potrebbe usare una tecnica del genere:
 template <class T>
 class polivector
 {
  vector<T*>	m_vect;
  public:
  polivector( int i = 0 ) : m_vect(i) { }
  ~polivector() { /* delete sugli elementi di m_vect... */ }
  template <class TT>
  void 	push_back( const TT& e )
  {
     m_vect.push_back( new TT(e) );		
  }
  T& operator[]( int i ) { return *m_vect[i]; }
 };
 polivector<Base> v;
 v.push_back( Derived1() );
 v[0].metodo_virtuale()
Max

 wrote :
| On Tue, 8 Aug 2000, Sandro wrote:
| >
| > [...]
| >
| > | void main()
| > | {
| > | std::vector<Cibo> vectCibo;
| >
| >   vectCibo.push_back(Pizza());
| >   vectCibo.push_back(Pizza());
|
| Attenzione che così il polimorfismo fa a farsi benedire. vectCibo
conterrà
| comunque dei veri oggetti Cibo, sebbene il push_back accetti un Pizza&.
Mannaggia alla fretta... hai ragione, intendevo un vector<Pizza>. Il
vector<Cibo> era per l'altro esempio, e nel cut&paste mi sono scordato di
correggere.