Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   C++ Builder (https://www.clubdelphi.com/foros/forumdisplay.php?f=13)
-   -   Problema Polimorfismo y Array bidimensiona[N][N] (https://www.clubdelphi.com/foros/showthread.php?t=69303)

Kandorf 09-08-2010 13:12:58

Problema Polimorfismo y Array bidimensiona[N][N]
 
Hola, estoy creando un juego y se me presenta el siguiente problema:
Los escenarios están divididos en Tiles(cuadraditos), para saber si puedo atravesar o no cada tile, tengo un array numérico.
He creado una clase padre TEscenario y quiero crear una subclase por cada escenario del juego (Si se os ocurre una idea mejor decídmelo).
La clase padre es algo así:
Código:

class TEscenario {
    public:
        TEscenario();
        (...)

        static const u8 Tiles[][]; // No sé cuántos elementos, sí se sabrá en cada clase que herede de ésta
};

y tengo la subclase Escenario1:
Código:

class Escenario1: public TEscenario{
    public:
        Escenario1();

        static const u8 Tiles[27][177];
};
Escenario1::Escenario1(){
    (...)
}
const u8 Escenario1::Tiles[27][177]=// Aquí lo inicializo, pero es demasiado largo para postearlo

El problema está en que en la clase padre da error la línea "static const u8 Tiles[][];", dice que en los array multidimensionales hay que indicar el tamaño de todas las dimensiones excepto de la primera, he probado a poner "static const u8 Tiles[]", pero al usar la segunda dimensión falla, como es lógico, también he probado "static const u8 **Tiles", pero al compilar falla en el linking.

He pensado que se podría solucionar dándole un límite de tamaño al array, pero no me gustaría darle un tamaño máximo a los escenarios.

Si utilizo la subclase directamente, sin el polimorfismo, funciona perfectamente, el problema es que no sé qué escenario tendré cargado y necesito el polimorfismo.

Saludos y gracias por las molestias.

LoPiTaL 09-08-2010 17:26:52

Lo único que se me ocurre es que en lugar de definir en la clase padre una variable de tipo array, definas una función que acepte dos argumentos (fila y columna) y ésta la sobreescribes en las clases hijas, las cuales sí tendrán una variable de tipo array, que sea privada, la cual se utilizará para devolver el valor adecuado de la función.

Ej (en Delphi y escrito ene el Chrome, así que igual cometo faltas):

Código:

TEscenario=class{
  public
    Constructor Create(); virtual; //Creo que es equivalente a TEscenario() de C...
    function Tiles(AFila, AColumna: integer): byte; virtual; abstract;  //La declaro abstract porque has dicho que en TEscenario no se sabe nada de los tiles....
}

TEscenario1=class(TEscenario)
{
  private
    fTiles: array [0..27-1] of array [0..177-1] of byte;
  public
    Constructor Create(); override;
    function Tiles(AFila, AColumna: integer): byte; override;
}

//Constructores, inicializaciones, etc...

function TEscenario1.Tiles(AFila, AColumna: integer): byte;
begin
  //Si quieres puedes incluso realizar alguna comprobación de que AFila y AColumna sean correctos...
  Result:=fTiles[AFila][AColumna];
end

Si quieres tener acceso también para escribir, simplemente defínete dos funciones setTile(AFila, AColumna: integer; AValor: byte) y getTile(AFila, AColumna: integer): byte, siguiendo más o menos el mismo principio mostrado.
En Delphi existe la posibilidad de usar las property, que puede acceder a una propiedad llamando a métodos de escritura / lectura. No sé si existe en C (creo que sí). Te he mostrado básicamente eso.

Espero te sirva de ayuda.
Un saludo,
LoPiTaL

escafandra 09-08-2010 18:27:55

Un array de dos simensiones en C/C++ no es ni mas ni menos que un ountero a un puintero, por lo tanto:
Código:

class TEscenario {
    public:
        TEscenario();
        (...)

        char ** Tiles;
};

En las clases hijas tendrás que dar la dimensión apropiada en el constructor de cada uno o después, en una función al efecto.


Código:

Tiles = new char*[Dimension1];
for(int n=0; n<Dimension1; n++)
        Tiles [n] = new char[Dimension2];

Para destruirlo sería igual.

Código:

for(int n=0; n<Dimension1; n++)
        delete [] Tiles [n];
delete [] Tiles:

Saludos.

Kandorf 10-08-2010 00:55:23

Hola a ambos, muchas gracias por vuestras respuestas.
escafandra, esa idea ya la había barajado y la tenía como última opción, ya que me parece muy engorroso tener que pedir la memoria en el constructor e introducir los valores, ya que son unos valores estáticos y definidos para cada subclase.

LoPiTaL, :eek: vaya PEDAZO de idea, no se me había ocurrido, pero es exactamente lo que busco: puedo inicializarlo fácilmente y puedo pedir los valores tan simple como Escenario.Tiles(N,N).

Muchas gracias a los dos, me habéis dado una alegría >.<

escafandra 10-08-2010 08:36:22

Cita:

Empezado por Kandorf (Mensaje 373030)
Hola a ambos, muchas gracias por vuestras respuestas.
escafandra, esa idea ya la había barajado y la tenía como última opción, ya que me parece muy engorroso tener que pedir la memoria en el constructor e introducir los valores, ya que son unos valores estáticos y definidos para cada subclase.

LoPiTaL, :eek: vaya PEDAZO de idea, no se me había ocurrido, pero es exactamente lo que busco: puedo inicializarlo fácilmente y puedo pedir los valores tan simple como Escenario.Tiles(N,N).

Muchas gracias a los dos, me habéis dado una alegría >.<

¿Pero que lenguaje vas a utilizar?. Entiendio que en C++. Pues bien, en C++ a secas no tienes arrays dinámicos, a no ser que te crees una clase al efecto.

Según lo que entiendo de tu último post, preendes hacer un miembro static de la clase. estos se declaran en la clase (archivo.h) y se inicializan fuera (archivo .cpp) en un lugar donde estemos seguros que se va a ejecutar.

Se trataría de hacer algo como esto:

Código:

class TEscenario {
    public:
    TEscenario();
    static BYTE **Tiles;
};

BYTE Tiles[][2] = {{1,2}, {2,3}}; // Los valores...
BYTE **TEscenario::Tiles = Tiles;

Estos miembros static solo pueden ser modificados por funciones también static de la clase, y serían comunes a todos los objetos que se creen de esa clase...

Creo que es esto lo que preguntas.

Saludos.

Kandorf 10-08-2010 12:09:20

Ya lo solucioné, hice esto:
Código:

class TEscenario {
    public:
        TEscenario();
        (...)

        virtual u8 Tile(u32 Y, u32 X)=0;
};

class Escenario1: public TEscenario{
    private:
        static const u8 Tiles[27][177];
    public:
        Escenario1();

        u8 Tile(u32 Y, u32 X);
};
u8 Escenario1::Tile(u32 Y, u32 X){
    return Tiles[Y][X];
}
const u8 Escenario1::Tiles[27][177]={inicializo}

Funciona perfectamente.

Sobre los archivos de cabecera, tengo un lío, se supone que en los .h declaras las variables y las funciones y en los .cpp las defines, ¿no? Lo he intentado pero me da problemas, será que no sé muy bien cómo va. ¿Tienen que llamarse igual cambiando la extensión y estar en la misma carpeta? ¿Al incluirlo con #include se especifica el .h y este ya sabe encontrar el .cpp?
Ahora mismo estoy utilizando sólo el .cpp, y es el que incluyo, funciona, pero me gusta hacer las cosas bien y me gustaría usar el .h.

Saludos.

escafandra 10-08-2010 15:54:12

Para los archivos cabecera de un proyecto, lo normal es que estén en la carpeta del cpp que los incluye. En ese caso se incluyen así:
Código:

#include "archivo.h"
Saludos.


La franja horaria es GMT +2. Ahora son las 19:11:42.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi