Trapicheando con C++ y SDL: Lío con Herencia :P

Iniciado por Ariath, 10 Julio 2010, 16:45 PM

0 Miembros y 1 Visitante están viendo este tema.

Ariath

Bueno, dado que estoy estudiando C++, y dado que me interesa aprender a desenvolverme minimamente con la SDL para realizar juegos sencillos en 2D, me he puesto a intentar programar un jueguecillo de naves simple (aprendo SDL y gano experiencia con C++, 2 pájaros de un tiro ^^ ).

Estoy desarrollando con la última versión de Code::Blocks, liberada hace nada (la 10.05), y con la copia de MinGW que traía (sip, me interesa que lo que haga sea multiplataforma).

Bueno al lío, resulta que estoy teniendo un problema con Herencia que no consigo resolver. Hay que decir que, en lo que llevo estudiado de C++ hasta ahora en la "uni", todavía no hemos tocado herencia, pero dado que he tenido contacto con ella en Java y C#, pues, leyendo un poco por ahí y otro poco por allá... van saliendo las cosas.


En fin, el problema es el siguiente: Tengo una clase Entity, la cual es esta:

Código (cpp) [Seleccionar]


#ifndef _ENTITY_H
#define _ENTITY_H

#include <iostream>
#include <SDL_Image.h>

class Entity{
protected:
SDL_Rect canvas;
SDL_Surface* graph;
bool alive;
int speed, acceleration;

public:
       Entity();
Entity(SDL_Surface* graph, Sint16 x, Sint16 y, int speed, int acceleration, bool alive);
void moveX(Sint16 amount);
void moveY(Sint16 amount);
SDL_Rect getCanvas();
SDL_Surface* getGraph();
int getSpeed();
int getAcceleration();
void setSpeed(int newSpeed);
void setAcceleration(int newAcceleration);

};

#endif


Código (cpp) [Seleccionar]


#include "Entity.h"

Entity::Entity(SDL_Surface* graph, Sint16 x, Sint16 y, int speed, int acceleration, bool alive){
   this->graph = graph;

canvas.x = x;
canvas.y = y;
canvas.h = this->graph->h;
   canvas.w = this->graph->w;

   this->speed = speed;
   this->acceleration = acceleration;
   this->alive = alive;
}

void Entity::moveX(Sint16 amount){
canvas.x += amount;
}

void Entity::moveY(Sint16 amount){
canvas.y += amount;
}

SDL_Rect Entity::getCanvas(){
   return canvas;
}

SDL_Surface* Entity::getGraph(){
return graph;
}

int Entity::getSpeed(){
   return speed;
}

int Entity::getAcceleration(){
   return acceleration;
}

void Entity::setSpeed(int newSpeed){
   speed = newSpeed;
}

void Entity::setAcceleration(int newAcceleration){
   acceleration = newAcceleration;
}



Y una clase Player:
Código (cpp) [Seleccionar]

#ifndef PLAYER_H_INCLUDED
#define PLAYER_H_INCLUDED

#include "Entity.h"

class Player: public Entity{
   private:
       bool mouseEnabled;
       bool keyboardEnabled;
       bool joystickEnabled;

       bool keyStates[233];

   public:
       Player(SDL_Surface* graph, Sint16 x, Sint16 y, int speed, int acceleration, bool alive);
       void enableControl(bool keyboard, bool mouse, bool joystick);
       void keyboardHandler(SDL_KeyboardEvent keyEv);
};

#endif // PLAYER_H_INCLUDED


Código (cpp) [Seleccionar]

#include "Player.h"

Player::Player(SDL_Surface* graph, Sint16 x, Sint16 y, int speed, int acceleration, bool alive){
   this->graph = graph;

canvas.x = x;
canvas.y = y;
canvas.h = this->graph->h;
   canvas.w = this->graph->w;

   this->speed = speed;
   this->acceleration = acceleration;
   this->alive = alive;
}

void Player::enableControl(bool keyboard, bool mouse, bool joystick){
   this->keyboardEnabled = keyboard;
   this->mouseEnabled = mouse;
   this->joystickEnabled = joystick;
}

void Player::keyboardHandler(SDL_KeyboardEvent keyEv){
   if(keyEv.type == SDL_KEYDOWN){
       keyStates[keyEv.keysym.sym] = true;
   }else if(keyEv.type == SDL_KEYUP){
       keyStates[keyEv.keysym.sym] = false;
   }


   if(keyStates[SDLK_UP]){
       moveY(-speed + acceleration);
   }

   if(keyStates[SDLK_RIGHT]){
       moveX(speed + acceleration);
   }

   if(keyStates[SDLK_DOWN]){
       moveY(speed + acceleration);
   }

   if(keyStates[SDLK_LEFT]){
       moveX(-speed + acceleration);
   }
}


(Perdonad el supertocho, pero la culpa es del foro por no tener una mala etiqueta Spoiler para "plegarlo" :P)

Bueno, como se puede ver, mi intención es que la clase Player herede de la clase Entity, añadiendo ciertas cosas que tienen sentido para un jugador, pero que no tienen porqué existir para entidad genérica (vease bicho, bonus, etc ...).

Esta es la parte del main donde creo el objeto:
Código (cpp) [Seleccionar]

Player* toad = new Player(graphPool->getGraph(0), 100, 100, 10, 0, true);


(Lo de "toad" es simplemente porque... porque me ha dado la gana de hacer las pruebas de superficie con el personajillo del mario XD)


En fin, me pongo a compilar el "invento", y el Code::Blocks me dice que nanai:
Cita de: CodeBlocks
||=== SDLGameTests, Debug ===|
M:\Documentos\Programacion\Proyectos\C++\SDLGameTests\main.cpp||In function 'int main(int, char**)':|
M:\Documentos\Programacion\Proyectos\C++\SDLGameTests\main.cpp|57|warning: taking address of temporary|
obj\Debug\Player.o||In function `Player':|
M:\Documentos\Programacion\Proyectos\C++\SDLGameTests\Player.cpp|3|undefined reference to `Entity::Entity()'|
M:\Documentos\Programacion\Proyectos\C++\SDLGameTests\Player.cpp|3|undefined reference to `Entity::Entity()'|
||=== Build finished: 2 errors, 1 warnings ===|

Los errores de la discordia son los ennegrecidos. Es decir, se ubican en la tercera línea del Player.cpp, justo donde comienza el constructor de la clase.

Llevo no se el tiempo ya tratando de intuir qué demonios me está queriendo decir el compilador con lo de "referencia sin definir" ...

¿Alguna idea? :P .

Salu2


P.D: Se me ha ocurrido hacer un cambio, eliminar el Entity(); del Entity.h:

Código (cpp) [Seleccionar]

public:
       Entity();
Entity(SDL_Surface* graph, Sint16 x, Sint16 y, int speed, int acceleration, bool alive);


Y el error que da ahora la compilación es este:

Cita de: CodeBlocks
M:\Documentos\Programacion\Proyectos\C++\SDLGameTests\Player.cpp||In constructor 'Player::Player(SDL_Surface*, Sint16, Sint16, int, int, bool)':|
M:\Documentos\Programacion\Proyectos\C++\SDLGameTests\Player.cpp|3|error: no matching function for call to 'Entity::Entity()'|
M:\Documentos\Programacion\Proyectos\C++\SDLGameTests\Entity.h|15|note: candidates are: Entity::Entity(SDL_Surface*, Sint16, Sint16, int, int, bool)|
M:\Documentos\Programacion\Proyectos\C++\SDLGameTests\Entity.h|7|note:                 Entity::Entity(const Entity&)|
||=== Build finished: 1 errors, 0 warnings ===|

leogtz

¿No será problema con el constructor vacío en la declaración de la clase "Entity"?

Aquí:
Citarpublic:
        Entity();

Quitalo o haz una implementación en el archivo correspondiente.

Saludos.
Código (perl) [Seleccionar]

(( 1 / 0 )) &> /dev/null || {
echo -e "stderrrrrrrrrrrrrrrrrrr";
}

http://leonardogtzr.wordpress.com/
leogutierrezramirez@gmail.com

Ariath

El tema es, que ese constructor al principio no lo tenía, es más, no lo necesito para nada, puesto que Entity tiene ya el constructor que quiero usar (y el que esperaba que usase la clase Player... antes de leer por algunos sitios que la clase hija no hereda los constructores y destructores de la padre :P ).

La cosa es que, eliminando ese constructor vacío, y dejando la Entity con el suyo, y la Player con el suyo, el compilador me da el error ese de "no matching function for call to 'Entity::Entity()'.

Por una parte, no entiendo por qué narices se pone a buscar ese constructor vacío... y todavía me deja más a cuadros, el hecho de que el compilador me marque como error la línea en la que empieza la implementación del constructor de Player.

O sea, yo declaro y construyo mi toad, y en cuanto se intenta construir (yendo a su constructor), el compilador me dice que nanai, y me habla de un constructor vacío Entity... no lo entiendo la verdad :P .

Salu2

Foxy Rider

Por que cuando heredás, también tenés que "llenar" los datos del constructor de la clase base ... fijate ...

Código (cpp) [Seleccionar]
Entity(SDL_Surface* graph, Sint16 x, Sint16 y, int speed, int acceleration, bool alive);

solo implementás ese constructor (es decir, abajo entre llaves indicás "que hace"), estando el que está sin parámetros sin implementar ....
ergo, la clase derivada "asume" (al no indicar el "pegamento" entre parámetros de la derivada y la base) que es el constructor sin parámetros .... y como no está implementado, tenés ese error, fijate ...

Código (cpp) [Seleccionar]
constructorDerivada(mArg1,mArg2,mArg3) : IBase1(mArg1),
  IBase1(mArg3),
{

/* cuerpo, las llamadas a los constructores de las clases base con los parametros "mapeados"
   ya esta especificado en el "pegamento" de arriba, aca haremos otras cositas muy especiales */
}



Espero haberme explicado bien  :-[

Saludos.

Ariath

Madre mía... no se si será imaginación mía, pero me parece que la herencia en C++ tiene más lío que en Java o C# :P .

Entonces, si te he entendido bien... y he entendido bien lo que he mirado en la web de C.Conclase, ¿la manera correcta de realizar el constructor de Player sería esta?:

Código (cpp) [Seleccionar]

Player(SDL_Surface* graph, Sint16 x, Sint16 y, int speed, int acceleration, bool alive): Entity(SDL_Surface* graph, Sint16 x, Sint16 y, int speed, int acceleration, bool alive)


¿O esta?:
Código (cpp) [Seleccionar]

Player(SDL_Surface* graph, Sint16 x, Sint16 y, int speed, int acceleration, bool alive): Entity(SDL_Surface* graph), Entity(Sint16 x), Entity(Sint16 y), Entity(int speed), Entity(int acceleration), Entity(bool alive)


Según de lo que he me he enterado, el constructor de la clase derivada tiene que proporcionar los datos necesarios al constructor de la clase base, puesto que se llama primero al de la clase derivada, y luego al de la clase base...

Salu2


P.D: Jo, al final tengo que tener, en ambas clases, un constructor que es calcado al 99% :P .

Foxy Rider

Nope, estás redeclarando el prototipo de Entity, cuando en realidad tenés que usar las variables del nuevo constructor ...

Código (cpp) [Seleccionar]
Player(SDL_Surface* graph, Sint16 x, Sint16 y, int speed, int acceleration, bool alive): Entity(graph,x, y, speed, acceleration,alive)

http://c.conclase.net/curso/index.php?cap=036b

Saludos.

Ariath

¡Oh, yeeeees! ¡¡¡Por fín funciona!!!! :D

Al principio he probado a sustituir la declaración del constructor de Player por esa, en la cabecera. Me ha dicho que faltaban unas llaves al final, con cara extrañada las añado, y veo que me dice que el constructor ya había sido definido (o algo así).

Total, que de pronto me hago a mí mismo un /facepalm, dejo la declaración del constructor de Player como estaba, me voy al Player.cpp, y cambio la primera línea del constructor por la que me has dado.

Y va de putísima madre :D .

Gracias por la ayuda, ya andaba como loco xD, me tengo que ver más a fondo todo el tema de la herencia en C++ :P .

Salu2 y tema solucionado ^^