C/Visual C - clases abstractas

 
Vista:

clases abstractas

Publicado por Franco Cedillo (4 intervenciones) el 10/08/2005 00:57:19
Hola,

En esta oportunidad estoy trabajando con clases abstractas. en el cuerpo principal del programa he declarado dos variables

Persona *Pepito = new Empleado("Jose", 1000);
Persona *Pablito = new Estudiante("Pablo", 7.56);

La clase persona es la siguiente

class Persona {
public:
Persona(char *n) { strcpy(nombre, n); }
virtual void Mostrar() = 0;
protected:
char nombre[30];
};

vemos en ella que el método Mostrar es virtual

Las clases derivadas Estudiante y Empleado son las siguientes

class Empleado : public Persona {
public:
Empleado(char *n, int s) : Persona(n), salario(s) {}
void Mostrar() const;
int LeeSalario() const { return salario; }
void ModificaSalario(int s) { salario = s; }
protected:
int salario;
};

void Empleado::Mostrar() const {
cout << "Empleado: " << nombre
<< ", Salario: " << salario
<< endl;
}

class Estudiante : public Persona {
public:
Estudiante(char *n, float no) : Persona(n), nota(no) {}
void Mostrar() const;
float LeeNota() const { return nota; }
void ModificaNota(float no) { nota = no; }
protected:
float nota;
};

void Estudiante::Mostrar() {
cout << "Estudiante: " << nombre
<< ", Nota: " << nota << endl;
}

lo importante en ellas es que el método Mostrar tiene un comportamiento diferente al tener que imprimir en pantalla diferentes tipos de variables.

lo que sigue en el cuerpo principal del programa es esto

char n[30];
Pepito->Mostrar();
Pablito->Mostrar();

Ambas llamadas son ilegales en el debug en tiempo de compilación. El error está en la declaración del método virtual pero no sé como corregirlo. en el lenguaje Eiffel se solucionaba con colocar la palabra reservada virtual antes de los métodos.

Saludos.

. he estado viendo los drafts de c99 y el website de code project y estoy muy interesado en aprender C# luego de concluir con un nivel básico de C++, porque he visto mucho que se hereda de otros lenguajes que simplifican la programación. Por ejemplo el trabajo con strings se parece al de pascal que es más sencillo. Pero limitado.
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

RE:clases abstractas

Publicado por fernando.gomez (1603 intervenciones) el 10/08/2005 01:34:48
Bueno, el chiste es que cuando sobreescribes un método declarado como virtual, tienes que seguir EXACTAMENTE LA MISMA FIRMA DEL METODO. En tu caso, no lo haces.

La declaración de Mostrar para Persona es:

void Mostrar();

Mientras, el método sobrecargado en Empleado es:

void Mostrar() const;

¿De dónde te sacas ese const? Ahí está el problema. O bien lo agregas a Persona::Mostrar, o lo quitas de las clases derivadas. Igual te sucede en Estudiante:

void Mostrar() const;

Peor aún, en la implementación de Estudiante::Mostrar NO incluyes el const:

void Estudiante::Mostrar() {
cout << "Estudiante: " << nombre
<< ", Nota: " << nota << endl;
}

Bueno, ese es el problemo principal. Afortunadamente este te sale en tiempo de compilación, pero tienes un error muchísimo más grave, que no te saldría en tiempo de compilación, sino de ejecución. Así, quizás te ahorre problemas ;-).

El problema está aquí:

Persona *Pepito = new Empleado("Jose", 1000);
Persona *Pablito = new Estudiante("Pablo", 7.56);

Asumo que eventualmente llegaremos a la siguiente línea de código:

delete Pepito;
delete Pablito;

para liberar los recursos de memoria, ¿no? Bueno, pues he aquí el gravísimo error. Esas sentencias te generarán comportamiento indefinido que, en el mejor de los casos, hará que el sistema truene.

¿Por qué? Bueno, porque aunque está permitido que un puntero apunte a una instancia de una clase derivada (Persona apunta a una clase Empleado/Estudiante que derivan de ella misma), el problema está en el destructor. Cuando hagas el delete, se mandará llamar al destructor de Persona, NO DE EMPLEADO / ESTUDIANTE. Y esto genera el comportamiento indefinido.

¿Solución? Agrega el modificador "virtual" a los destructores de Empleado y Estudiante:

// respectivamente
virtual ~ Empleado();
virtual ~Estudiante();

Aguas con esto; el problema de los comportamientos indefinidos es que _A_VECES_ funcionan, por azares del destino. Pero vas a ver cómo fallan justo cuando le estés entregando el programa a tu cliente (o al profe).

Por otro lado, si ya te estás leyendo el estándar de C, quizás te convenga leerte el de C++. El libro de Bjärne Stroustrup es la mejor referencia.

Finalmente, qué bueno que estés interesado en C#. Microsoft ya sacó C# 2.0, con la incorporación de la programación genérica. Y otras mafufadas: en ciertos casos puedes regresar ¡varios valores! con yield return. Imagina:

public int Pares()
{
yield return 2;
yield return 4;
yield return 6;
yield return 8;
yield return 10;
}

regresará una referencia a IEnumerable<int> que contendrá todos esos valores. Como los parámetros variables de C o los params de C#, pero al revés. ¡Qué cosas!

Saludos.



Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar