Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Clases Abstractas: Polimorfismo

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 11

POLIMORFISMO

Clases abstractas
Una clase abstracta, normalmente ocupa una posición alta en la jerarquía de clases que le
permite actuar como un depósito de métodos y atributos compartidos para las subclases de
nivel inmediatamente inferior. Las clases abstractas definen un tipo generalizado y sirven
solamente para describir nuevas clases.
Las clases abstractas no tienen instancias directamente. Se utilizan para agrupar otras clases
y capturar información que es común al grupo. Sin embargo, las subclases de clases abstractas
se corresponden a objetos del mundo real y pueden tener instancias. Las superclases que se
crean a partir de subclases con atributos y comportamientos comunes, y que sirven para
derivar otras clases que comparten sus características, son clases abstractas.
En C++ una clase abstracta tiene al menos una función miembro que se declara pero no se
define, su definición se realiza en la clase derivada. Estas funciones miembro se denominan
funciones virtuales puras, cuya definición formal es:
Virtual tipo nombreFuncion(argumentos) = 0;
Las siguientes reglas se aplican a las clases abstractas:

 Una clase abstracta debe tener al menos una función virtual pura.
 Una clase abstracta no se puede utilizar como un tipo de argumento o como un tipo
de retorno de una función aunque si un puntero a ella.
 No se puede declarar una instancia de una clase abstracta.
 Se puede utilizar un puntero o referencia a una clase abstracta.
 Una clase derivada que no proporcione una definición de una función virtual pura,
también es una clase abstracta.
 Cada clase (derivada de una clase abstracta) que proporcione una definición de todas
sus funciones virtuales es una clase concreta.
 Solo esté permitido crear punteros a las clases abstractas y pasárselos a funciones.
FUNCIONES VIRTUALES
Si la palabra reservada virtual precede a la declaración de una función, esta función se llama
virtual y le indica al compilador que puede ser definida (implementado su cuerpo) en una
clase derivada y que en este caso la función se invocará directamente a través de un puntero.
Se debe calificar una función miembro de una clase con la palabra reservada virtual solo
cuando exista una posibilidad de que otras clases puedan ser derivadas de aquella.
Un uso común de las funciones virtuales es la declaración de clases abstractas y la
implementación del polimorfismo.

Ejemplo:
Una clase base Animal podría tener una función virtual come. La subclase Pez implementaría
come() de forma diferente que la subclase Lobo, pero se podría invocar a come() en cualquier
instancia de una clase referida como Animal, y obtener el comportamiento de come() de la
subclase específica.

Animal
Lobo Pez OtroAnimal
come() come() come()

Esto permitiría a un programador procesar una lista de objetos de la clase Animal, diciendo a
cada uno que coma (llamando a come()), sin saber qué tipo de animales hay en la lista.
Tampoco tendría que saber cómo come cada animal, o cuántos tipos de animales puede llegar
a existir.

#include <iostream>
using namespace std;
class Animal
{
public:
virtual void come() { cout << "Yo como como un animal genérico.\n"; }
virtual ~Animal() {}
};

class Lobo : public Animal


{
public:
void come() { cout << "¡Yo como como un lobo!\n"; }
virtual ~Lobo() {}
};

class Pez : public Animal


{
public:
void come() { cout << "¡Yo como como un pez!\n"; }
virtual ~Pez() {}
};

class OtroAnimal : public Animal


{
virtual ~OtroAnimal() {}
};
int main(int argc, char *argv[]) {
Animal *unAnimal[4];
unAnimal[0] = new Animal();
unAnimal[1] = new Lobo();
unAnimal[2] = new Pez();
unAnimal[3] = new OtroAnimal();

for(int i = 0; i < 4; i++) {


unAnimal[i]->come();
}

for (int i = 0; i < 4; i++) {


delete unAnimal[i];
}
return 0;
}

Salida con el método virtual come:

Yo como como un animal genérico.


¡Yo como como un lobo!
¡Yo como como un pez!
Yo como como un animal genérico.

Salida sin el método virtual come:

Yo como como un animal genérico.


Yo como como un animal genérico.
Yo como como un animal genérico.
Yo como como un animal genérico.

POLIMORFISMO

En POO, el polimorfismo permite que diferentes objetos respondan de modo diferente al


mismo mensaje. El polimorfismo adquiere su máxima potencia cuando se utiliza en unión de
la herencia.
La forma más adecuada de usar polimorfismo es a través de punteros.
Para poder utilizar polimorfismo en C++ se deben seguir las siguientes reglas:
1. Crear una jerarquía de clases con las operaciones importantes definidas por las
funciones miembro declaradas como virtuales en la clase base.
2. Las implementaciones específicas de las funciones virtuales se deben hacer en las
clases derivadas. Cada clase derivada puede tener su propia versión de las funciones.
3. Las instancias de estas clases se manipulan a través de una referencia o un puntero.

Ejemplo 1: Definir la clase padre persona y las subclases alumno y profesor y la función virtual
mostrar(), que muestre información personal de cada una de las clases hijas

#include <iostream>
using namespace std;

class persona {
private:
string nombre;
int edad;
public:
persona (string nom, int ed){
nombre = nom;
edad = ed;
}
virtual void mostrar(){
cout<<"nombre: "<<nombre<<endl;
cout<<"Edad: "<<edad<<endl;
}
};

class alumno: public persona {


private:
int nota;
public:
alumno(string nom, int ed, float nt): persona(nom, ed){
nota = nt;
}
void mostrar(){
persona::mostrar();
cout<<"Nota: "<<nota<<endl;
}
};

class profesor: public persona{


private:
string curso;
public:
profesor(string nom, int ed, string cu):persona(nom, ed){
curso = cu;
}
void mostrar(){
persona::mostrar();
cout<<"Curso: "<<curso<<endl;
}
};

int main(int argc, char *argv[]) {

persona *datos[3];

datos[0] = new alumno("José", 20, 16.5);


datos[1] = new alumno("Maria", 22, 18.7);
datos[2] = new profesor("Torres", 42, "Administración");

datos[0] -> mostrar();


datos[1] -> mostrar();
datos[2] -> mostrar();

return 0;
}
Ejemplo 2: Definir una clase forma que sea una clase base abstracta que contenga la interfaz
hacia la jerarquía. Derive a dosDimensiones y tresDimensiones de la clase forma, que también
serán abstractas. Utilice una función print virtual para enviar a la salida el tipo y dimensiones
de cada figura. También incluye funciones virtual area y volume para que estos cálculos
puedan realizarse para los objetos de cada clase concreta de la jerarquía.
Escriba un programa controlador que pruebe la jerarquía de la clase forma.

#include <iostream>
#include <cmath>
using namespace std;
// clase forma

class forma {
public:
virtual double area() const { return 0.0; }
virtual double volumen() const { return 0.0; }

// funcion virtual pura sobrepuesta en las clases derivadas


virtual void print() const=0;
};

////////////////////////////////
// clase DosDimensiones ///
////////////////////////////////

class DosDimensiones : public forma {


public:
virtual void print () const=0;
};

// clase triangulo
class triangulo : public DosDimensiones {
double lado1, lado2, lado3;
public:
triangulo (double=0.0, double=0.0, double=0.0);
void fijar_triangulo(double, double, double);
virtual double area() const;
virtual void print() const;
};

triangulo :: triangulo (double l1, double l2, double l3){


fijar_triangulo(l1,l2,l3);
}
void triangulo :: fijar_triangulo (double l1, double l2, double l3){
lado1= l1 > 0 ? l1 : 0;
lado2= l2 > 0 ? l2 : 0;
lado3= l3 > 0 ? l3 : 0;
}

double triangulo :: area () const {


double s;
s=(lado1+lado2+lado3)/2;

return sqrt(s*(s-lado1)*(s-lado2)*(s-lado3));
}

void triangulo :: print () const {


cout << endl << "Triangulo" << endl
<< "Lado 1= " << lado1 << endl
<< "Lado 2= " << lado2 << endl
<< "Lado 3= " << lado3;
}

// clase cuadrado
class cuadrado : public DosDimensiones {
double lado;
public:
cuadrado (double=0.0);
void fijar_cuadrado(double);
virtual double area() const;
virtual void print() const;
};

cuadrado :: cuadrado (double l) {


fijar_cuadrado(l);
}

void cuadrado :: fijar_cuadrado (double l){


lado= l>0 ? l : 0;
}

double cuadrado :: area () const {


return lado*lado;
}

void cuadrado :: print() const {


cout << endl << "Cuadrado" << endl
<<"Lado= " << lado;
}

////////////////////////////////
// clase tresDimensiones /
////////////////////////////////

class tresDimensiones : public forma {


public:
virtual void print () const=0;
};

// clase cubo
class cubo : public tresDimensiones {
double lado;
public:
cubo(double=0.0);
void fijar_cubo(double);
virtual double area() const;
virtual double volumen() const;
virtual void print() const;
};

cubo :: cubo (double l){


fijar_cubo(l);
}

void cubo :: fijar_cubo (double l){


lado= l>0 ? l : 0;
}

double cubo :: area () const {


return 6*lado*lado;
}

double cubo :: volumen () const {


return lado*lado*lado;
}

void cubo :: print() const{


cout << endl << "Cubo" << endl
<<"Lado= " << lado;
}
// clase paralelepipedo
class paralelepipedo : public tresDimensiones {
double largo, ancho, altura;
public:
paralelepipedo(double=0.0, double=0.0, double=0.0);
void fijar_paralelepipedo(double, double, double);
virtual double area() const;
virtual double volumen() const;
virtual void print() const;
};

paralelepipedo :: paralelepipedo (double l, double a, double h){


fijar_paralelepipedo(l,a,h);
}

void paralelepipedo :: fijar_paralelepipedo (double l, double a, double h){


largo= l>0 ? l : 0;
ancho= a>0 ? a : 0;
altura= h>0 ? h : 0;
}

double paralelepipedo :: area () const {


return 2*largo*ancho + 4*ancho*altura;
}

double paralelepipedo :: volumen () const {


return largo*ancho*altura;
}

void paralelepipedo :: print() const{


cout << endl <<"Paralelep¡pedo" << endl
<<"Largo= " << largo << endl
<<"Ancho= " << ancho << endl
<<"Altura= " << altura;
}

// llama a funcion virtual a partir del apuntador de clase base


// utilizando enlace dinamico
void virtualViaPointer (const forma* baseClassPtr){
baseClassPtr->print();
cout << endl <<"Area= " << baseClassPtr->area() << endl
<<"volumen= " << baseClassPtr->volumen() << endl;
}
// llama a funcion virtual a partir de referencia a clase base
// utilizando enlace dinamico
void virtualViaReference (const forma& baseClassRef){
baseClassRef.print();
cout << endl <<"Area= " << baseClassRef.area() << endl
<<"volumen= " << baseClassRef.volumen() << endl;
}
int main(int argc, char *argv[]) {

triangulo t(5.2,6.5,7.1);
virtualViaPointer (& t);
virtualViaReference (t);

cuadrado c(8.7);
virtualViaPointer (&c);
virtualViaReference (c);

cubo cub(8.3);
virtualViaPointer (&cub);
virtualViaReference (cub);

paralelepipedo p(4.5,6.7,9.2);
virtualViaPointer (&p);
virtualViaReference (p);
return 0;
}

Ejercicio:

1. Definir la clase objeto geométrico y las clases círculo y cuadrado que hereden las
coordenadas del centro de un círculo y de un cuadrado respectivamente. La clase
círculo deberá permitir calcular la longitud de la circunferencia y el área del círculo de
radio dado. La clase cuadrado debe permitir calcular el perímetro y el área del
cuadrado conociendo además un vértice del cuadrado.

Sugerencia:

También podría gustarte