2009-06-09 13 views
10

Estoy tratando de crear una clase como tal:¿Hay alguna manera de inicializar una matriz con variables no constantes? (C++)

class CLASS 
{ 
public: 
    //stuff 
private: 
    int x, y; 
    char array[x][y]; 
}; 

Por supuesto, esto no funciona hasta que cambie int x, y; a

const static int x = 10, y = 10; 

cual es poco práctico, porque estoy tratando para leer los valores de xey de un archivo. Entonces, ¿hay alguna manera de inicializar una matriz con valores no contantes, o declarar una matriz y declarar su tamaño en diferentes declaraciones? Y sé que esto probablemente requeriría la creación de una clase de matriz, pero no estoy seguro de dónde comenzar con esto, y no quiero crear una lista dinámica 2D cuando la matriz en sí misma no es dinámica, solo el tamaño es no conocido en tiempo de compilación.

Respuesta

9

la necesidad compilador para tener el tamaño exacto de la clase al compilar, tendrá que usar el nuevo operador para asignar dinámicamente la memoria.

Cambiar matriz de caracteres [x] [y]; char ** array; e inicialice su matriz en el constructor, y no olvide eliminar su matriz en el destructor.

class MyClass 
{ 
public: 
    MyClass() { 
     x = 10; //read from file 
     y = 10; //read from file 
     allocate(x, y); 
    } 

    MyClass(const MyClass& otherClass) { 
     x = otherClass.x; 
     y = otherClass.y; 
     allocate(x, y); 

     // This can be replace by a memcopy 
     for(int i=0 ; i<x ; ++i) 
      for(int j=0 ; j<x ; ++j) 
       array[i][j] = otherClass.array[i][j]; 
    } 

    ~MyClass(){ 
     deleteMe(); 
    } 

    void allocate(int x, int y){ 
     array = new char*[x]; 
     for(int i = 0; i < y; i++) 
      array[i] = new char[y]; 
    } 

    void deleteMe(){ 
     for (int i = 0; i < y; i++) 
      delete[] array[i]; 
     delete[] array; 
    } 

    MyClass& operator= (const MyClass& otherClass) 
    { 
     if(this != &otherClass) 
     { 
      deleteMe(); 
      x = otherClass.x; 
      y = otherClass.y; 
      allocate(x, y); 
      for(int i=0 ; i<x ; ++i) 
       for(int j=0 ; j<y ; ++j) 
        array[i][j] = otherClass.array[i][j];    
     } 
     return *this; 
    } 
private: 
    int x, y; 
    char** array; 
}; 

* EDIT: he tenido el constructor de copia y el operador de asignación

+0

y para acceder a un elemento en particular, podría decir array [xpos] [ypos] ;? –

+0

Sí Keand64, simplemente use array [xpos] [ypos]; –

+4

Eso es malo. ¿Qué hay de la construcción de copias? Operador de asignación. ¿Por qué no tener toda la memoria en un bloque contiguo en lugar de una matriz de matrices? ¿Qué pasa con el manejo de excepciones en el constructor? –

1

No puede asignar o inicializar una matriz global o estática declarativamente utilizando valores no constantes (tiempo de compilación). Sin embargo, es posible para matrices locales (matrices de tamaño variable C99, ya que su inicializador se ejecuta esencialmente en tiempo de ejecución cada vez que se ejecuta la función).

Por su situación, se sugiere emplear un puntero en lugar de una matriz y crear la matriz real dinámicamente en tiempo de ejecución (utilizando new):

class CLASS 
{ 
public: 
    CLASS(int _x, int _y) : x(_x), y(_y) { 
     array = new char*[x]; 
     for(int i = 0; i < x; ++i) 
      array[i] = new char[y]; 
    } 
    ~CLASS() { 
     for (int i = 0; i < x; ++i) 
      delete[] array[i]; 
     delete[] array; 
    } 
    //stuff 
private: 
    int x, y; 
    char **array; 
}; 
+0

elabora por favor? –

+0

Estaba hablando de asignación e inicialización, en general. Una matriz cuyo tamaño no se conoce es dinámica. No se puede asignar mágicamente memoria estáticamente sin saber la cantidad. –

+1

Eso es malo. ¿Qué hay de la construcción de copias? Operador de asignación. ¿Por qué no tener toda la memoria en un bloque contiguo en lugar de una matriz de matrices? ¿Qué pasa con el manejo de excepciones en el constructor? –

0

Si el tamaño no se conoce en tiempo de compilación, la matriz es dinámica. Lo que podrías hacer para mantenerlo estático es hacerlos más grandes que tu tamaño más grande esperado.

+0

Lo que causará un error de compilación si ese tamaño excede el espacio disponible en un marco de pila (generalmente 4k). –

+0

Por supuesto, pero él no quiere usar memoria dinámica? – CookieOfFortune

0

Si desea una matriz de tamaño dinámico como miembro de la clase, debe anexar new y asignar ese valor a un puntero. La sintaxis char array[size] es solo para matrices de tamaño estático.

Mejor aún, realmente debería utilizar un std::vector< std::vector<char> >, hay muy pocas buenas razones para trabajar manualmente con matrices de tamaño dinámico en estos días.

15

use vector.

#include <vector> 
class YourClass 
{ 
public: 
    YourClass() 
    : x(read_x_from_file()), y(read_y_from_file()) 
    { 
     my_array.resize(x); 
     for(int ix = 0; ix < x; ++ix) 
      my_array[ix].resize(y); 
    } 

    //stuff 

private: 
    int x, y; 
    std::vector<std::vector<char> > my_array; 
}; 
+1

Bueno como una solución "estrictamente estándar", pero seguramente 'boost :: multi_array' también merece una mención? –

+0

Puede hacer todo en línea sin un bucle: ': x (read_x_from_file()), y (read_y_from_file()), my_array (x, vector (y)) {}'. Dicho esto, haría tanto la lectura del archivo como la asignación en el cuerpo del ctor. Intento mantener los efectos secundarios que hace un ctor-initializer en una cantidad mínima absoluta. –

+0

'use vector' ¿cómo es eso una opción cuando la función que llamo tiene firma para una matriz? :/ – n611x007

4
No

de esa manera, como en C++, tamaños de matriz c-estilo tiene que ser conocido en tiempo de compilación, con algunas extensiones específicas de proveedores que permiten ciertos tamaños de tiempo de ejecución (para mejorar la compatibilidad con C99), pero no en el situación que está describiendo (si está interesado, here's a description). La cosa más fácil de hacer sería:

std::vector< std::vector<char> > array; 

Y aplicar el tamaño en el constructor:

array.resize(x); 
for(std::vector< std::vector<char> >::iterator curr(array.begin()),end(array.end());curr!=end;++curr){ 
    curr->resize(y); 
} 

Hay muchas ventajas de vector sobre matrices de estilo c, ver here

2

Ponga toda la memoria en un solo bloque.
Como es privado, puede obtener sus métodos de acceso para recuperar el valor correcto.

Ejemplo rápido:

#include <vector> 
#include <iostream> 

class Matrix 
{ 
    public: 
    class Row 
    { 
     public: 
     Row(Matrix& p,unsigned int x) 
      :parent(p) 
      ,xAxis(x) 
     {} 
     char& operator[](int yAxis) 
     { 
      return parent.data(xAxis,yAxis); 
     } 
     private: 
      Matrix&   parent; 
      unsigned int xAxis; 
    }; 

    Matrix(unsigned int x,unsigned int y) 
     :xSize(x) 
     ,ySize(y) 
     ,dataArray(x*y) 
    {} 

    Matrix::Row operator[](unsigned int xAxis) 
    { 
     return Row(*this,xAxis); 
    } 
    char& data(unsigned int xAxis,unsigned int yAxis) 
    { 
     return dataArray[yAxis*xSize + xAxis]; 
    } 
    private: 
     unsigned int xSize; 
     unsigned int ySize; 
     std::vector<char> dataArray; 
}; 


int main() 
{ 
    Matrix  two(2,2); 

    two[0][0] = '1'; 
    two[0][1] = '2'; 
    two[1][0] = '3'; 
    two[1][1] = '4'; 

    std::cout << two[1][0] << "\n"; 
    std::cout << two.data(1,0) << "\n"; 
} 
+0

Nice one. Tendré que recordar ese truco. – Luis

1

Puede asignar memoria a su matriz bidimensional en el constructor y liberarla en el destructor. La forma más simple:

array = (char **)malloc(sizeof(char *) * x); 
if (array) { 
    for (i = 0; i < x; i++) { 
     array[i] = (char *)malloc(sizeof(char) * y); 
     assert(array[i]); 
    } 
} 
Cuestiones relacionadas