2011-12-22 7 views
5

Estoy tratando de implementar una matriz dinámica:matriz utilizando plantillas bidimensionales

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]; 
} 

Cuando se utiliza de esta manera, funciona como se esperaba, es decir, grabados 5:

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

Sin embargo, lo haría me gusta usar la clase para una matriz dinámica bidimensional. Pensé que lo siguiente simplemente funcionaría mágicamente e imprimiría 5 ...

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

... pero no funciona. Se bloquea cuando intento establecer el valor en [0] [0]. El depurador me muestra que this tiene _size establecido en 0 y _array en NULL. this en ese punto apunta al primer elemento del _array de la última instancia de Array creada.

Una de las cosas que no entiendo es cuando la matriz "interna" llama a su constructor. Al recorrer el código, veo que Array(int size) se llama una vez y Array() cinco veces. Me gustaría crear la matriz interna con un tamaño específico, pero no se compila con Array< Array<int>(10) > testArray(5).

¿Podría darme algo de información sobre esto? Parece que todavía no podía entender bien las plantillas ...

Respuesta

6

No se pueden encadenar llamadas de constructor en C++. La primera implementación de constructor no hace nada, por lo que las 5 instancias contenidas en el elemento primario Array terminan sin inicializarse, lo que da como resultado un comportamiento no definido.

Para solucionarlo, puede agregar un valor predeterminado al parámetro size del otro constructor, o factorizar la lógica de inicialización en una función separada (privada), y llamarla desde ambos constructores.

EDITAR: La razón por la cual el primer constructor no hace nada es que la línea

Array(5) 

no llama al constructor de la instancia actual, sino que asigna un nuevo (sin nombre) temporal Array ejemplo, que es inmediatamente destruido al final de la línea.

+0

¡Oh, no sabía que no podría encadenar llamadas de constructor! Ahora creo una función privada y ahora funciona, pero solo con el tamaño especificado en el constructor predeterminado. ¿Alguna idea sobre cómo crear la matriz interna con un tamaño dinámico? – fabian789

+0

Si usa C++ 11 ** y ** el tamaño de la matriz externa es estáticamente conocido, puede usar una lista de inicializadores para proporcionar los inicializadores para todas las matrices internas. De todos modos, me olvidé de escribir eso en mi respuesta, pero a menos que esto sea algo más que un ejercicio, la verdadera solución es usar 'std :: vector'. –

+0

Sí, es solo un ejercicio. ¿Podría decirme qué quiere decir con "lista de inicializadores"? usar '_array = new Item [size] (size);' no compila para mí. – fabian789

1

No puede llamar a otra ctor desde su ctor predeterminado. Si desea tener un valor predeterminado, puede combinar los dos en 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; 
} 

Sin embargo si todavía prefieren tener los dos ctor entonces se puede mover la aplicación a una función privada _setup que puede ser utilizado tanto como este.

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; 
} 

Edited para eliminar inicializador inválido para array newed.

+0

Agregar (tamaño) después de que los corchetes [] no compilen para mí ...? – fabian789

+0

Parece que me he adelantado y olvidé que no se puede especificar un inicializador para las matrices con la nueva instrucción. Quizás sería ideal usar un vector en lugar de un puntero a una matriz. Sospecho que esto para la clase y no puedes usar cualquier stl existente. – jbreiding

+0

Sí, es solo un ejercicio :) – fabian789

Cuestiones relacionadas