C++ : herencia

Buenos días.

Hace tiempo que estoy desarrollando un juego para NDS, y tengo el siguiente problema:
En dicho juego hay fichas, pero hay muchos tipos diferentes de fichas. Por lo tanto tengo una clase "ficha.h" y otras que son subclases de ésta, pongamos por ejemplo "fichaNormal.h" (entre otras).
El problema es que tengo una matriz de elementos de tipo "ficha", y me gustaría hacer la llamada siguiente:

matrizDeFichas[0][0].dibujar();

matrizDeFichas sería una matriz que contendría fichas de todo tipo, y dibujar la operación que las muestra por pantalla.
El caso es que, si por ejemplo en matrizDeFichas[0][0] hubiera una "fichaNormal", el programa llama a la operación dibujar() de Ficha y no de FichaNormal, que es lo que me interesaría.

¿Cómo podría hacerlo?

Gracias.
pon virtual delante de la funcion dibujar de ficha

PD: Estás usando memoria estática (de la pila vamos) o dinámica? Porque si no es dinámica y la has hecho del tipo Ficha, estás bien jodido.
Si "dibujar()" es igual para todas las fichas declara el método en la clase padre (ficha) y listo. Si es un método especifico de cada tipo de ficha (que este es tu problema) declaralo como virtual (busca la esplicación en la página web de "c con clase") en la case padre y lo redefines en cada hijo.

EDIT: Corregido fallo del cerebro, que puso abstract donde quería poner virtual.
es tan fácil como poner virtual en la función dibuja y en caso de necesitarlo redefinirla en los hijos.... si no vas a tener instancias de fichas puedes hacer la función virtual pura

esto sería

virtual void dibuja() = 0 ;

así no tienes que declarar dibuja en ficha.h

lo que dicen es cierto para poder usar polimorfismo será necesario que estes gastando memoria dinámica ya que en otro caso el compilador decidiría el tipo en la compilación y accederá la función del tipo que has declarado. Así que hazlo con puteros
Muchas gracias a todos, menuda cabeza la mía. Además, como indica saulotmalo será virtual pura.

Saludos [oki]
saulotmalo escribió:lo que dicen es cierto para poder usar polimorfismo será necesario que estes gastando memoria dinámica ya que en otro caso el compilador decidiría el tipo en la compilación y accederá la función del tipo que has declarado. Así que hazlo con puteros

No necesariamente tiene que ser dinámica. Puedes utilizar referencias o punteros y crear los objectos en memoria estática, cambiando la referencia/puntero en tiempo de ejecución por medio del operador referencia (&).

Lo digo porque si el juego tiene un número fijo de fichas durante todo el juego (o un total máximo de ellas aceptable) podría ser factible crear todos los objetos ficha necesarios estáticos:

#include

using namespace std;

class Ficha
{
public:
virtual void Dibuja() = 0;
};

class FichaNormal : public Ficha
{
public:
virtual void Dibuja()
{

std::cout << "Soy una ficha normal" << std::endl;
}
};

class FichaRara : public Ficha
{
public:
virtual void Dibuja()
{

std::cout << "Soy una ficha rara" << std::endl;
}
};



int main()
{
FichaNormal fichaNormalObj;
FichaRara fichaRaraObj;

Ficha* ptrFicha = 0;

ptrFicha = &fichaNormalObj;

ptrFicha->Dibuja();

ptrFicha = &fichaRaraObj;

ptrFicha->Dibuja();

std::cin.get();

return 0;
}


Lo importante del polimorfismo no es que la memoria sea dinámica, sino que utilices la dirección de memoria de la variable para que en tiempo de ejecución, se pueda aplicar el desplazamiento a dicha dirección para llamar a la función virtual correspondiente en la vtable.
Buena observación zheo, gracias.
El número de fichas no es fijo así que estoy usando una matriz de punteros a ficha ;)

Un saludo!
cierto, culpa mia!

no sé en que estaba pensando, está que con memoria estática puedes hacer polimorfismo pero di la verdad, en la práctica se gasta muy poco! pero bueno si el ejemplo que has puesto es bueno si tienes un número fijo de elementos, pero lo normal es en un juego tener un número variable de elementos que suben y bajan y no sueles reservar por el máximo aunque te ahorrarías luego el coste de usar memoria dinámica desperdiciarías espacio como si fuese estático pero con la ventaja del polimorfismo y la complicación de los punteros.
saulotmalo escribió:cierto, culpa mia!

no sé en que estaba pensando, está que con memoria estática puedes hacer polimorfismo pero di la verdad, en la práctica se gasta muy poco! pero bueno si el ejemplo que has puesto es bueno si tienes un número fijo de elementos, pero lo normal es en un juego tener un número variable de elementos que suben y bajan y no sueles reservar por el máximo aunque te ahorrarías luego el coste de usar memoria dinámica desperdiciarías espacio como si fuese estático pero con la ventaja del polimorfismo y la complicación de los punteros.

Si pero no. Puedes implementar un pool de objetos reutilizables en sistemas o aspectos donde reservar/liberar memoria sea prohibitivo, (por ejemplo para muchos objectos pequeños) con objectos estáticos.

Y como complicación añado que hacer un delete a un puntero que apunta a un objeto estático es malo :P
zheo


Ese ejemplo es muy bónito para enseñar pero irrealista. Lo normal es que las clases hija no tengan el mismo tamaño que las padre.

Otra cosa es que tengas un pool de objetos del mismo tipo ya creado o un pool de memoria sin más.
webez escribió: Ese ejemplo es muy bónito para enseñar pero irrealista. Lo normal es que las clases hija no tengan el mismo tamaño que las padre.

¿Y cuál es el problema con eso?
webez escribió:

Ese ejemplo es muy bónito para enseñar pero irrealista. Lo normal es que las clases hija no tengan el mismo tamaño que las padre.

Otra cosa es que tengas un pool de objetos del mismo tipo ya creado o un pool de memoria sin más.

¿Qué es un "pool"?

Saludos
Es una forma de eliminar la reserva de memoria dinámica, o minimizarla para evitar problemas. Por ejemplo si necesitas un montón de objetos pequeños en un momento dado de un juego (por ejemplo partículas) es costoso reservar y desalojar memoria según se vayan creando y destruyendo. Además eso posiblemente fragmente la memoria.
Lo que haces con un pool, es inicializar un montón de esos objetos de una tacada. Cuando quieres "crear" un nuevo objeto lo que haces es utilizar uno de los objetos ya creados del pool, simplemente lo inicializas con los valores que quieres y lo usas. Y cuando quieres "destruirlo" simplemente lo marcas como no utilizado, para que más adelante pueda ser reutilizado.

Así siempre tienes los objetos inicializados en memoria y te ahorras reservar y liberar. El problema es que aunque no los uses siguen ocupando, por eso digo que compensa cuando son objetos pequeños, y muchos, que se crean y se destruyen en gran cantidad.
zheo


Pues que se te jode el chiringuito de hacer un array estático de objetos clase base. Joderías los objetos.
No no no no, lo que harías sería crear estáticamente los objetos derivados, y luego por medio de un puntero o referencia a la clase base , referenciarlos, "el tamaño no importa" (TM)

Nada tiene que ver el tamaño de los objetos con usar polimorfismo.
zheo


Si yo me refiero a que tu le has dicho que podría crear todos los objetos ficha estáticamente. Porque tu me dirás para que va a hacer la chorrada de si está creando un objeto estáticamente, obtener una referencia de tipo base para llamara al método virtual. Para eso sobreescribe las función sin más en las clases derivadas y a correr.

Estamos mezclando churros con pepinillos. Yo no hablo de polimofirmos en ningún momento, sino del problema de crear un array estático de objetos clase base metiendo objetos de clase derivada. Por mi como si ninguna función. Si quiere un array (o la estructura que quiera) de varios objetos de diferentes clases derivadas, está claro que tiene que hacerlo dinámicamente (no va a hacer un array estáticos por clase derivada y luego uno de punteros a la clase base digo yo)
webez escribió: Si yo me refiero a que tu le has dicho que podría crear todos los objetos ficha estáticamente. Porque tu me dirás para que va a hacer la chorrada de si está creando un objeto estáticamente, obtener una referencia de tipo base para llamara al método virtual. Para eso sobreescribe las función sin más en las clases derivadas y a correr.

Pues para lo mismo que quieres el polimorfismo, para llamar a varias métodos de clases de distinto tipo, pero con una clase base común...

Estamos mezclando churros con pepinillos. Yo no hablo de polimofirmos en ningún momento, sino del problema de crear un array estático de objetos clase base metiendo objetos de clase derivada. Por mi como si ninguna función. Si quiere un array (o la estructura que quiera) de varios objetos de diferentes clases derivadas, está claro que tiene que hacerlo dinámicamente (no va a hacer un array estáticos por clase derivada y luego uno de punteros a la clase base digo yo)

¿Y por qué no va a poder hacer eso último? Puede ser útil en ciertas circunstancias.

Sin embargo si estoy de acuerdo en que estamos mezclando cosas. Yo sólo dije que para usar polimorfismo NO necesitas memoria dinámica.
supongo que lo que zheo decía es que tenía la posibilidad de hacerlo aunque como le he dicho yo no tiene porque y sería más cómodo declarar la memoria como dinámica y listo
saulotmalo escribió:supongo que lo que zheo decía es que tenía la posibilidad de hacerlo aunque como le he dicho yo no tiene porque y sería más cómodo declarar la memoria como dinámica y listo

Exacto.

Lo normal es hacerlo dinamico claro, porque dado un puntero/referencia a una clase base, tienes la ventaja de asignarlo a una instancia de la clase derivadas según te convenga, cambiando el comportamiento como prefieras creando y destruyendo los objetos "al vuelo".

Sólo decía que podría darse el caso de que hacerlo con objetos alojados estáticamente fuera conveniente, y que no hay ningún problema en ese caso.

Por ejemplo en J2ME si puedes evitar crear y destruir objetos en el loop de juego pues mucho mejor para tí y tu stress. En J2ME no hay diferencia entre estática y dinámica (creo)
Pero ello no quita que si fuera necesario, en C++ definas una clase base Sprite con métodos para dibujar, tengas un PersonajeJugadorSprite, y listas de Enemigo1Sprite, Enemigo2Sprite cradas estáticamente (por ejemplo porque sabes que puedes tener un máximo de 3 enemigos1 y 2 enemigos2 en pantalla. Pues puedes crear arrays estáticos para los objetos de los dos tipos de enemigos, y luego crear un array de referencias / punteros a sprites, meter ahí el jugador y todos los enemigos y dibujarlos usando polimorfismo. ;)
Es que es que el ejemplo de polimorfismo con objetos estáticos es muy "didáctico" pero como digo inútil

Ya que

FichaNormal fichaNormalObj;
FichaRara fichaRaraObj;

fichaNormalObj.Dibuja();

fichaRaraObj.Dibuja();

llama igualmente a las funciones dibujar de las clases derivadas. Por eso insisto, en que no digo que no se pueda usar polimorfismo (que no lo he dicho en ninguno de los anteriores post). Lo que digo es que es bastante absurdo hacer las cosas asi (y más cuando llamar función virtual es más "caro")


PD2: En J2ME todo se crea en la heap salvo que le metas un static (cosa que se hace un webo para tener una aplicación más rápida). Otra cosa es que los sistemas que trabajan con J2ME suelen tener más bien poca stack
webez escribió:Es que es que el ejemplo de polimorfismo con objetos estáticos es muy "didáctico" pero como digo inútil

Ya que

FichaNormal fichaNormalObj;
FichaRara fichaRaraObj;

fichaNormalObj.Dibuja();

fichaRaraObj.Dibuja();

Cambiemos el ejemplo:

State* ptrCurrentState;

GameState gameStateObj();
MenuState menuStateObj();

ptrCurrentState = &menuStateObj;

while (!endGame)
{
ptrCurrentState->Update();
Screen.Present();
}


Que si, que es más fácil y cómodo dinámicamente, pero puede tener sus usos.

PD2: En J2ME todo se crea en la heap salvo que le metas un static (cosa que se hace un webo para tener una aplicación más rápida). Otra cosa es que los sistemas que trabajan con J2ME suelen tener más bien poca stack

Thx!
zheo


Sus usos claro que tiene (el último ejemplo por ejemplo es "didáctico" y además "útil"). Pero no creo que el de usarlo para arrays de objetos estáticos sea uno de los más interesantes.

Esperemos que después de tanta charla Nocrala no diga al menos que no fue por opciones :P
De variedad no se puede quejar no
:-p
estos "pikes" o vs de informáticos me recuerdan a los típicos concursos de raperos, no os pasa igual? xD

mola que el foro vuelve a tener algo de vidilla a ver que comenta el creador del hilo.
23 respuestas