Tengo una duda sobre redefinición de funciones virtuales en C++

Iniciado por theluigy13etv, 20 Febrero 2015, 17:01 PM

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

theluigy13etv

Hola :) , estoy intentando hacer el juego de pacman en modo consola en mis ratos de ocio y de pasada me voy recordando algunas cosas que ya me estaba olvidando y afianzando otros conceptos sobre la programación orientada a objetos.

Expondré lo que hice hasta ahora y luego mi duda. No es tanto sobre el código sino más que todo en cuanto a cómo funciona lo de la redefinición de una función virtual.

Resulta que tengo tres clases: PERSONAJE, PACMAN, FANTASMA:

Clase Personaje:
Código (cpp) [Seleccionar]

class PERSONAJE {
  private:
     int x, y;   // Coordenadas
     int simbolo;
     
  public:
     PERSONAJE(int = 1, int = 1, int = 1);
     void setX(int);
     void setY(int);
     void setSimbolo(int);
     int getX();
     int getY();
     int getSimbolo();
     virtual void mover(int);
     void pintar();
     void borrar();
};

/*
void PERSONAJE::PERSONAJE(int x, int y, char simbolo) {
  this->setX(x);
  this->setY(y);
  this->setSimbolo(simbolo);
}
*/

PERSONAJE::PERSONAJE(int _x, int _y, int _simbolo) : x(_x), y(_y), simbolo(_simbolo) {
  this->pintar();
}

void PERSONAJE::setX(int x) {
  this->x = (x > 0 ? x : 1);
  // x = (x > 0 ? x : 1); // Cuidado con este error logico, alli no estaria modificando al atributo
}

void PERSONAJE::setY(int y) {
  this->y = (y > 0 ? y : 1);
}

void PERSONAJE::setSimbolo(int simbolo) {
  this->simbolo = simbolo;
}

int PERSONAJE::getX() {
  return this->x;
}

int PERSONAJE::getY() {
  return this->y;
}

int PERSONAJE::getSimbolo() {
  return this->simbolo;
}

void PERSONAJE::mover(int tecla) {
 
  if (tecla == NADA) {
     return;
  }
  else {
     this->borrar();
     
     if (tecla == IZQUIERDA) {
        if (x > LIMITE_IZQUIERDO + 1) x--;
     }
 
     if (tecla == DERECHA) {
        if (x < LIMITE_DERECHO - 1) x++;
     }
 
     if (tecla == ABAJO) {
        if (y < LIMITE_INFERIOR - 1) y++;
     }
 
     if (tecla == ARRIBA) {
        if (y > LIMITE_SUPERIOR + 1) y--;
     }
     
     this->pintar();
  }
}

void PERSONAJE::pintar() {
  gotoxy(x, y);
  cout << (char)getSimbolo();
}

void PERSONAJE::borrar() {
  gotoxy(x, y);
  cout << " ";
}





Clase Pacman:
Código (cpp) [Seleccionar]

class PACMAN : public PERSONAJE {
  private:

  public:
     PACMAN(int = LIMITE_IZQUIERDO + 1, int = LIMITE_SUPERIOR + 1, int = 1);
     // No redefinimos el metodo pintar() asi que se llamara al de la superclase
};

PACMAN::PACMAN(int x, int y, int simbolo) : PERSONAJE(x, y, simbolo) {
}




Clase Fantasma:
Código (cpp) [Seleccionar]

class FANTASMA : public PERSONAJE {
  private:
     
  public:
     FANTASMA(int = (LIMITE_IZQUIERDO + LIMITE_DERECHO) / 2, int = (LIMITE_SUPERIOR + LIMITE_INFERIOR) / 2, int = 1);
     void mover();
};

FANTASMA::FANTASMA(int x, int y, int simbolo) : PERSONAJE(x, y, simbolo) {
}

void FANTASMA::mover() {
  int aleatorio = rand() % 4;
 
  this->borrar();
 
  switch (aleatorio) {
     case 0:
        if (getX() > LIMITE_IZQUIERDO + 1) setX(getX() - 1);
        break;
       
     case 1:
        if (getX() < LIMITE_DERECHO - 1) setX(getX() + 1);
        break;
       
     case 2:
        if (getY() < LIMITE_INFERIOR - 1) setY(getY() + 1);
        break;
       
     case 3:
        if (getY() > LIMITE_SUPERIOR + 1) setY(getY() - 1);
        break;
  }
 
  gotoxy(getX(), getY());
  this->pintar(); // Llama al método heredado pintar
}


Algunas constantes en mi código:
Código (cpp) [Seleccionar]

// Direccion
#define ARRIBA 105
#define ABAJO 107
#define IZQUIERDA 106
#define DERECHA 'l'

// Limites
#define LIMITE_SUPERIOR 2
#define LIMITE_INFERIOR 23
#define LIMITE_DERECHO 70
#define LIMITE_IZQUIERDO 20

#define NADA 0



Mi duda está en lo siguiente:
En mi clase base PERSONAJE defino una función virtual mover(int) la cual tiene un parámetro. Luego, declado dos clases derivadas: PACMAN y FANTASMA.
Dentro de la clase PACMAN (por el momento) no declaro ninguna otra función por lo que concluyo que va a heredar las ya declaradas en la clase base PERSONAJE.
Dentro de la clase FANTASMA estoy declarando una función llamada mover() sin parámetros. Esta función tiene el mismo nombre que la función virtual declarada en la clase base PERSONAJE pero se diferencia en que no tiene ningún parámetro. Entonces ante la duda de si en este caso estoy redefiniendo la función perteneciente al padre, encontré la siguiente información:

CitarPara redefinir una función virtual en una clase derivada, las declaraciones en la clase base y en la derivada deben coincidir en cuanto a número y tipo de los parámetros. Excepcionalmente pueden diferir en el tipo devuelto.

Entonces según esto, la función mover() perteneciente a la clase hija FANTASMA es diferente a la función mover(int) de la clase padre PERSONAJE (por su parámetro) por lo que podría concluir que no se estaría redefiniendo nada sino que, la clase FANTASMA contaría con dos funciones miembro diferentes:
   - mover()    : Obtenida por la herencia y declarada en el padre PERSONAJE
   - mover(int) : Declarada en la clase hija FANTASMA

Además de las otras funciones heredadas del padre: getX(), getY(), getSimbolo(), setX(int), setY(int), setSimbolo(int), .. , borrar(), pintar().


Siendo todo esto así, creo que no debería tener problemas al realizar llamadas tanto a las funciones mover() y mover(int) desde un objeto de la clase FANTASMA pero cuando realizo dichas llamadas, el compilador me genera un error márcandome esta llamada: f1.mover(IZQUIERDA);:


Código (cpp) [Seleccionar]

FANTASMA f1;
f1.mover();
f1.mover(IZQUIERDA);





No sé si me estoy haciendo demasiados rodeos  ;D . Espero que me haya dejado entender. Gracias a los que se tomen la molestia de leer y de ayudarme a entender el por qué me sale ese error :D . (Si pudieran también comentar sobre mi código, acepto sugerencias y críticas para poder mejorar. Respecto a la biblioteca conio tengo claro que no es estándar pero en este caso lo que trato más que todo es centrarme en aplicar correctamente los conceptos de la POO)

_Enko

Haz el metodo virtual que quieres sobreescribir en la clase derivada como "override".  Si no hay nada que sobreescribir, el compilador tendría que protestar. De esa manera te aseguras que estas sobreescribiendo un metodo de la clase Padre.

No solo importa el nombre del metodo, sino los argumentos y el tipo devuelto.
move(void) no es lo mismo que move(int).


Saludos.