2011-12-22 23 views
5

Sto cercando di implementare un array dinamico:matrice bidimensionale utilizzando i modelli

template <typename Item> 
class Array { 
private: 
    Item *_array; 
    int _size; 
public: 
    Array(); 
    Array(int size); 
    Item& operator[](int index); 
}; 

template <typename Item> 
Array<Item>::Array() { 
    Array(5); 
} 

template <typename Item> 
Array<Item>::Array(int size) { 
    _size = size; 
    _array = new Item [size]; 

    for (int i = 0; i < size; i++) 
     cout << i << " " << _array[i] << " " << &_array[i] << endl; 
} 

template <class Item> 
Item& Array<Item>::operator[](int index) { 
    if (index < 0 || index > _size-1) 
     cout << "this: " << this << ". Index out of range" << endl; 

    return _array[index]; 
} 

Quando viene usato in questo modo, funziona come previsto, vale a dire stampe 5:

Array<int> testArray(5); 
testArray[0] = 5; 
cout << testArray[0] << endl; 

Tuttavia, vorrei piace usare la classe per un array dinamico bidimensionale. Ho pensato che il seguente avrebbe funzionato e stampato magicamente 5 ...

Array< Array<int> > testArray(5); 
testArray[0][0] = 5; 
cout << testArray[0][0] << endl; 

... ma non funziona. Si blocca quando provo a impostare il valore su [0] [0]. Il debugger mi mostra che this ha _size impostato su 0 e _array su NULL. this in quel punto punta al primo elemento di _array dell'ultima istanza di Array creata.

Una delle cose che non ottengo è quando l'array "interno" chiama il suo costruttore. Passando attraverso il codice, vedo che Array(int size) viene chiamato una volta e Array() cinque volte. Vorrei creare l'array interno con una dimensione specifica, ma l'utilizzo di Array< Array<int>(10) > testArray(5) non viene compilato.

Potresti fornirmi qualche informazione su questo? Sembra che non riesco ancora a spiegarmi i modelli ...

risposta

6

Non è possibile concatenare chiamate del costruttore in C++. La prima implementazione del costruttore non fa nulla, quindi le 5 istanze contenute nel genitore Array finiscono per essere non inizializzate, con conseguente comportamento indefinito.

Per risolvere il problema, è possibile aggiungere un valore predefinito al parametro size dell'altro costruttore o troncare la logica di inizializzazione in una funzione separata (privata) e chiamarlo da entrambi i costruttori.

EDIT: La ragione per cui il primo costruttore non fa nulla è che la linea

Array(5) 

non chiama il costruttore dell'istanza corrente, ma invece alloca un nuovo (senza nome) temporaneo Array esempio, che viene immediatamente distrutto alla fine della linea.

+0

Oh, non sapevo che non potevi associare le chiamate del costruttore! Ora ho creato una funzione privata e ora funziona, ma solo con le dimensioni specificate nel costruttore predefinito. Qualche idea su come creare l'array interno con una dimensione dinamica? – fabian789

+0

Se si utilizza C++ 11 ** e ** la dimensione dell'array esterno è staticamente nota, è possibile utilizzare un elenco di inizializzatori per fornire gli inizializzatori per tutti gli array interni. Ad ogni modo, ho dimenticato di scriverlo nella mia risposta, ma a meno che questo non sia altro che un esercizio, la vera soluzione è usare 'std :: vector'. –

+0

Sì, è solo un esercizio. Potresti dirmi cosa intendi con "lista di inizializzazione"? usando '_array = new Item [size] (size);' non mi viene compilato. – fabian789

3

Usa valore predefinito per il costruttore di chiamare senza argomentazione vale a dire Array(int index = 5);

Si prega di verificare questo: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.3

Può un costruttore di una classe chiamata un altro costruttore della stessa classe per inizializzare l'questo oggetto?

+0

Grazie per il link! – fabian789

1

Non è possibile chiamare un altro operatore dal proprio operatore predefinito. Se si desidera avere un valore predefinito, è possibile combinare i due in uno.

template <typename Item> 
Array<Item>::Array(int size = 5) { 
    _size = size; 
    _array = new Item [size]; 

    for (int i = 0; i < size; i++) 
     cout << i << " " << _array[i] << " " << &_array[i] << endl; 
} 

Tuttavia, se si preferisce ancora avere due ctor allora si può passare l'implementazione di una funzione _setup privata che può essere utilizzata da entrambi come questo.

template <typename Item> 
Array<Item>::Array() { 
    _setup(5); 
} 

template <typename Item> 
Array<Item>::Array(int size) { 
    _setup(size); 
} 

template <typename Item> 
void Array<Item>::_setup(int size) { 
    _size = size; 
    _array = new Item [size]; 

    for (int i = 0; i < size; i++) 
     cout << i << " " << _array[i] << " " << &_array[i] << endl; 
} 

Modificato per rimuovere l'inizializzatore non valido per l'array nuovo.

+0

L'aggiunta (dimensione) dopo le parentesi [] non viene compilata per me ...? – fabian789

+0

Quindi sembrerebbe che mi sono messo in testa e ho dimenticato che non è possibile specificare un inizializzatore per gli array con la nuova istruzione. Forse utilizzare un vettore piuttosto che un puntatore a un array sarebbe l'ideale. Sospetto questo se per la classe e non è possibile utilizzare qualsiasi stl esistente. – jbreiding

+0

Sì, è solo un esercizio :) – fabian789

Problemi correlati