Newsgroup: it.comp.lang.c++
Titolo: Array di classi

Vi espongo il problema: data una determinata classe, per esempio Vettore, vi
risulta che sia possibile inizializzare un array di puntatori di elementi
della classe Vettore in questo modo?:
Vettore *ptr;
...
ptr[i] = new Vettore[dim];
...
dove dim è il numero di elementi del vettore.
Ho provato ad usare questo pezzo di codice, ma il compilatore mi dice che
non riesce a trovare il costruttore di default della classe Vettore, credo
riferendosi all'uso delle [].
Inoltre, tenendo conto del fatto che il costruttore con argomenti della
classe Vettore è proprio Vettore::Vettore(dim), ho ritentato correggendo in
questo modo:
...
ptr[i] = new Vettore(dim);
...
e questa volta non mi ha dato errore, ma la cosa non mi torna tanto...
Ringrazio chiunque abbia voglia di rispondere.
Cecco

Ringrazio chiunque abbia voglia di rispondere.
Non sono sicuro di aver capito il tuo messaggio... tu hai una
classe che non ha un costruttore di default e vuoi inizializzare
un array di istanze di questa classe ? Se e' cosi' per il
momentro tralascio che questa classe si chiami "vettore"
(secondo me aggiunge solo confusione alla cosa).
La risposta e' che non si puo' fare con gli array allocati
dinamicamente (questi infatti inizializzano gli elementi usando
il costruttore di default). Come valida alternativa puoi usare
std::vector che e' piu' comodo degli array... es:
  #include <vector>
  class MyClass
  {
    public:
      MyClass(int x,int y); // Costruttore
    ...
  };
  int main()
  {
    std::vector<MyClass> vett(100,MyClass(10,10));
    ... usi gli elementi vett[i] ...
  }
La prima linea di main() crea un vettore di 100 elementi myclass
dove ciascuno e' stato ottenuto copiando l'elemento MyClass(10,10).
Non e' esattamente quello che chiedi ma ci va abbastanza vicino.
Nota anche che il "100" della linea di dichiarazione puo' essere
un valore calcolato e che gli oggetti std::vector possono essere
ridimensionati durante l'esecuzione.
Per fare esattamente quello che chiedi bisogna usare un sistema
molto piu' complicato e in cui e' molto piu' facile fare errori:
  #include <memory>
  class MyClass
  {
    public:
      MyClass(int x,int y); // Costruttore
    ...
  };
  int main()
  {
    // Allocazione della memoria necessaria
    MyClass *ptr = (MyClass *)operator new[](100*sizeof(MyClass));
    // Costruzione degli oggetti nella memoria allocata
    for (int i=0; i<100; i++)
      new (ptr+i) MyClass(10,10);
    ... usi gli elementi ptr[i] ...
    // Distruzione elementi
    for (int i=0; i<100; i++)
      ptr[i].~MyClass();
    // Deallocazione memoria
    operator delete[](ptr);
    return 0;
  }
Personalmente ti sconsiglio fortemente questa seconda strada.
Nota che ad esempio con std::vector non ti devi preoccupare della
deallocazione o della distruzione degli elementi contenuti.
HTH
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

 deallocazione o della distruzione degli elementi contenuti.
In effetti volevo solo sapere se la strada che avevo scelto era quella
giusta o se avevo trascurato qualche aspetto; grazie comunque per il
chiarimento.
Cecco

 dove dim è il numero di elementi del vettore.
Attento. Hai detto che vuoi inizializzare un arrai di puntatori. Ma la
dichiarazione "Vettore *ptr;" crea un puntatore a Vettore. A questo puntatore
puoi assegnare l'indirizzo ritornato allocando un array di Vettore. Ma ti
sottolineo la differenza fra 'array di Vettore' e 'array di puntatori a
Vettore'. Nel primo caso ogni elemento dell'array e' un puntatore (e ciascuno
puo' puntare ad un Vettore dierso, tutti allo stesso, tutti NULL etc). Nel
secondo caso ciascun elemento dell'array e' una istanza di Vettore.
Il secondo errore e' che assegni il risultato della allocazione all'i-esimo
elemento dell'array puntato da ptr. A parte il fatto che non hai inizializzato
il puntatore ptr (almeno non nel codice postato), per come lo hai dichiarato
l'i-esimo elemento di un array di Vettore e' un Vettore. Pertanto stai
assegnando il risultato della new ad un oggetto di tipo Vettore. Dubito che sia
quello che volevi.
Se vuoi un array di Vettore (allocato dinamicamente con ciascun elemento
inizializzato con un costruttore di default) fai cosi:
// occhio che cosi' non e' inizializzato
Vettore *ptr;
// alloca un array di n oggetti Vettore
// ciascuno viene costruito con il costruttore di default
ptr = new Vettore[n];
...
// libera la memoria occupata dall'array
// e chiama i distruttori dei vari Vettore
delete [] ptr;
Se invece vuoi un array di puntatori a Vettore devi fare cosi (uso il typedef
per semplificarti la sintassi ed evitare confusione):
typedef Vettore *PtrVettore;
// occhio che cosi' non e' inizializzato
// questa definizione e' equivalente a "Vettore**ptr;"
PtrVettore *ptr;
// alloca un array di n puntatori
// occhio che devi poi inizializzarli uno per uno
ptr = new PtrVettore[n];
// inizializza i puntatori
for ( int i=0; i<n; ++i )
    // se vuoi qui puoi usare un costruttore diverso
    // da quello di default per inizializzare i Vettore
    ptr[i] = new Vettore;
...
// prima di disallocare l'array devi disallocare
// gli oggetti puntati (chiamando i distruttori)
for ( int i=0; i<n; ++i )
    delete ptr[i];
// libera la memoria occupata dall'array
delete [] ptr;
Comunque un consiglio: se lavori in C++, usa std::vector che e' molto piu'
semplice.
--
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556