Beruflich Dokumente
Kultur Dokumente
5.6. Abstracción.
5.7. Polimorfismo.
En esta sección no se pretende dar una teoría completa de P.O.O. tan sólo se presentarán los
conceptos necesarios para una correcta programación en C++ Builder.
Objeto: Una entidad autónoma con una funcionalidad concreta y bien definida.
Clase: Especificación de las características de un conjunto de objetos.
Un objeto es una instancia de una clase.
Los conceptos presentados en esta sección se ilustrarán usando un ejemplo que se irá
completando poco a poco a medida que se introduzcan nuevos conceptos. Es más, este
mismo ejemplo se emplea en las secciones dedicadas al tratamiento de excepciones y a la
programación con hebras. Así, preparemos el camino creando un proyecto:
Colocar un botón bit que permita terminar la ejecución del programa. El botón
estará centrado horizontalmente en la parte inferior del formulario.
Crear una unidad (File | New | Unit). Guardarla con el nombre ObjGraf.cpp
Cuando se crea una unidad de esta manera se crean, en realidad, dos ficheros,
uno con extensión .cpp y otro con extensión .h. Así, disponemos de dos
ficheros: ObjGraf.h, que contendrá las declaraciones de las clases con las que
vamos a trabajar, y ObjGraf.cpp, que contendrá la definición (implementación de
los métodos) de éstas.
En ObjGraf.h:
//--------------------------------------------------
#ifndef ObjGrafH
#define ObjGrafH
#endif
//--------------------------------------------------
Muy Importante: Con el ejemplo anterior sólo conseguimos definir la clase, pero no se
crea ningún objeto.
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 2/24
5/12/2017 Programación Orientada a Objetos en C++
Un objeto se puede instanciar de una forma simple, declarando una variable del
tipo de la clase.
En Ppal.h:
#include "ObjGraf.h"
En Ppal.cpp:
//--------------------------------------------------
//--------------------------------------------------
Creación Dinámica
Cuando usamos new para instanciar un objeto, se usa una variable que referencie
o apunte al nuevo objeto creado (de otra manera éste quedaría totalmente
inaccesible). En definitiva, se requiere la declaración previa de un puntero a
objetos del tipo del que se va a crear.
En Ppal.cpp:
TObjGraf * ObjGraf; // Variable Global.
// ObjGraf es un puntero a objetos de tipo TObjGraf
//--------------------------------------------------
//--------------------------------------------------
Destrucción de objetos
Cuando un objeto deja de ser útil hay que eliminarlo. De esta manera la
aplicación recupera los recursos (memoria) que ese objeto había acaparado
cuando se creó.
En Ppal.cpp:
//--------------------------------------------------
//--------------------------------------------------
5.3. Encapsulamiento
En la programación clásica (lenguaje C, p.e.) existen datos y procedimientos que actúan
sobre esos datos. No hay una relación aparente entre datos y procedimientos (funciones) y
esta relación se establece de manera más o menos pecisa de acuerdo a la profesionalidad del
programador.
En P.O.O. los datos y los procedimientos que los gestionan están relacionados
explícitamente y se "encapsulan" en un objeto. La especificación de las propiedades de un
objeto y los métodos de acceso se realiza en la declaración de la clase de la que se instancia
el objeto.
En la figura 5.2 esquematizamos las propiedades y métodos que se van a asociar a los
objetos de la clase TObjGraf:
En ObjGraf.h:
//--------------------------------------------------
class TObjGraf {
public:
int X; // Propiedades
int Y;
TColor Color;
TPaintBox *PaintBox;
//--------------------------------------------------
Para acceder a los miembros de un objeto se usan los operadores típicos de acceso a
miembros: el operador . para referencia directa al objeto y el operador -> para acceso a
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 5/24
5/12/2017 Programación Orientada a Objetos en C++
través de un puntero. Como nosotros siempre creamos los objetos con new, y los
referenciamos mediante un puntero, el operador de acceso que utilizaremos es el operador -
>
En Ppal.cpp:
//--------------------------------------------------
//--------------------------------------------------
Nota: Los puntos suspensivos no son una palabra reservada de C++, simplemente significan
que se omite una parte del código, ya sea porque es irrelevante o porque ya se ha expuesto
anteriormente.
En ObjGraf.h:
class TObjGraf {
...
En ObjGraf.cpp:
TObjGraf :: TObjGraf (TPaintBox * _PaintBox, TColor _Color,
int _X, int _Y)
{
PaintBox = _PaintBox;
Color = _Color;
X = _X;
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 6/24
5/12/2017 Programación Orientada a Objetos en C++
Y = _Y;
}
En Ppal.cpp:
void __fastcall TPpalFrm::FormCreate(TObject *Sender)
{
ObjGraf = new TObjGraf (PaintBox, clRed, 10, 10);
}
5.5. Herencia
Cuando una clase hereda de otra, la clase derivada incorpora todos los miembros de la
clase base además de los suyos propios.
Tomando como base la clase TObjGraf se van a construir dos nuevas clases, TCirculo y
TCuadrado, que derivan de TObjGraf. Esto significa que los objetos de estas clases tienen
asociados las propiedades y métodos de la clase base, TObjGraf, además de los suyos
propios. En la figura 5.3 esquematizamos el mecanismo de herencia para las nuevas clases y
las nuevas propiedades que se asocian a los objetos de las clases derivadas.
Figura 5.3. Las clases TCirculo y TCuadrado heredan las propiedades y métodos de la clase
TObjGraf.4
En ObjGraf.h:
//*************************************************/
// Definicion de la clase derivada TCirculo
// Deriva de la clase base TObjGraf
//*************************************************/
public:
};
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 7/24
5/12/2017 Programación Orientada a Objetos en C++
//*************************************************/
// Definicion de la clase derivada TCuadrado.
// Deriva de la clase base TObjGraf
//*************************************************/
public:
};
Antes del nombre de la clase base hay que poner public, esto es así porque C++ permite
también la herencia private. Pero ésta no se suele usar, por lo que nosotros supondremos
que sólo existe la public.
Los constructores y destructores de una clase no son heredadas automáticamente por sus
descendientes. Deberemos crear en las clases hijas sus propios constructores y destructores.
Es posible, no obstante, emplear los constructores de la clase base pero hay que indicarlo
explícitamente. De ser así, es necesario saber:
Para determinar con qué parámetros se llaman a los constructores de las clases base, se
utiliza la lista de inicialización.
En ObjGraf.h:
//*************************************************/
// Definicion de la clase derivada TCirculo
// Deriva de la clase base TObjGraf
//*************************************************/
public:
// Metodo constructor
};
//*************************************************/
// Definicion de la clase derivada TCuadrado.
// Deriva de la clase base TObjGraf
//*************************************************/
public:
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 8/24
5/12/2017 Programación Orientada a Objetos en C++
// Metodo constructor
};
En ObjGraf.cpp:
TCirculo :: TCirculo (TPaintBox * _PaintBox, TColor _Color,
int _X, int _Y, int _Radio) :
TObjGraf (_PaintBox, _Color, _X, _Y)
{
Radio = _Radio;
}
Clase abstracta: es una clase que no está completamente especificada (posee métodos sin
implementar), por lo tanto no se pueden crear instancias de la misma. Una clase abstracta
se usa para servir de clase base a otras clases. En terminología C++ se dice que una clase
abstracta es aquella que posee al menos un método virtual puro.
En ObjGraf.h:
class TObjGraf {
public:
...
// Otros metodos
public:
...
};
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 9/24
5/12/2017 Programación Orientada a Objetos en C++
public:
...
};
En ObjGraf.cpp:
void TCirculo :: Mostrar (void)
{
PaintBox->Canvas->Pen->Color = Color;
PaintBox->Canvas->Brush->Color = Color;
PaintBox->Canvas->Ellipse(X, Y, X+Radio*2, Y+Radio*2);
}
...
¿Por qué se especifica el método Mostrar en TObjGraf, como virtual puro, en lugar de
omitirlo? Fundamentalmente podemos considerar dos razones para usar métodos virtuales
puros:
Para obligar a que las clases descendientes los implementen. De esta forma
estamos seguros de que todas las clases descendientes no abstractas de TObjGraf
poseen el método, y se podrá invocar con seguridad.
//--------------------------------------------------
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 10/24
5/12/2017 Programación Orientada a Objetos en C++
//--------------------------------------------------
//--------------------------------------------------
//--------------------------------------------------
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 11/24
5/12/2017 Programación Orientada a Objetos en C++
Ejercicio:
Figura 5.5. Resultado del proyecto Ejemplo.bpr mostrando objetos de la clase TTriangulo.
La herencia múltiple es el hecho de que una clase derivada se genere a partir de varias
clases base.
Ejemplo:
class TVehiculo {
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 12/24
5/12/2017 Programación Orientada a Objetos en C++
int NumRuedas;
...
};
Observar que los objetos de la clase TCocheEnVenta derivan de las clases TProducto y
TVehiculo.
Existen dos formas para que una clase saque partido de las ventajas de otra, una es la
herencia, y la otra es que una clase contenga un objeto de la otra clase.
Ninguna de las dos posibilidades es mejor que la otra, en cada caso particular habrá que
estudiar cual es la mejor opción.
Por ejemplo, si quisieramos diseñar una clase (TMarco) que represente un marco
(representado por un cuadrado y un círculo), podemos decidir distintas estrategias a la hora
de llevarlo a cabo:
5.6. Abstracción
Es la ocultación de detalles irrelevantes o que no se desean mostrar. Podemos distinguir en
una clase dos aspectos desde el punto de vista de la abstracción:
Resumiendo: nos interesa saber qué nos ofrece un objeto, pero no cómo lo lleva a cabo.
En C++ se puede especificar el acceso a los miembros de una clase utilizando los siguientes
especificadores de acceso:
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 13/24
5/12/2017 Programación Orientada a Objetos en C++
protected: desde los métodos de la clase y desde los métodos de las clases
derivadas.
En ObjGraf.h:
//*************************************************/
// Definicion de la clase base TObjGraf
//*************************************************/
class TObjGraf {
int X;
int Y;
TColor Color;
TPaintBox * PaintBox;
// Otros metodos
};
Modificar de la misma manera las clases TCirculo y TCuadrado para que sus propiedades
Radio y Lado queden protegidas y los métodos públicos:
//*************************************************/
// Definicion de la clase derivada TCirculo.
// Deriva de la clase base TObjGraf
//*************************************************/
int Radio;
public:
// Metodo constructor
//*************************************************/
// Definicion de la clase derivada TCuadrado.
// Deriva de la clase base TObjGraf
//*************************************************/
int Lado;
public:
// Metodo constructor
//--------------------------------------------------
En realidad estos tres especificadores de acceso son los propios de C++, pero en C++
Builder existe otro adicional, que es el __published. No vamos a dar mucha importancia a
este modificador, porque su uso está restringido al IDE. Cuando en una clase veamos una
sección __published quiere decir que los miembros contenidos en la misma son mantenidos
automáticamente por el IDE y no deberemos modificar nada en dicha sección, ya que de lo
contrario los resultados pueden ser imprevisibles.
Son propiedades definidas mediante métodos de lectura (read) y/o escritura (write). Se
llaman virtuales porque, realmente, no existen. El usuario de la clase usa estas propiedades
como si fueran propiedades reales y en última instancia se traducen en la llamada a un
método o en el acceso a una propiedad real. Es más, si una propiedad virtual se usa para
lectura (p.e. en la parte derecha de una asignación) se traduce en una acción diferente que si
esa popiedad virtual se usa para escritura. La acción que se produce cuando la propiedad
virtual es de lectura se especifica, sintácticamente, mediante la palabra reservada read
mientras que si se usa para escritura se especifica con write. Veamos un ejemplo.
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 15/24
5/12/2017 Programación Orientada a Objetos en C++
En ObjGraf.h:
//*************************************************/
// Definicion de la clase base TObjGraf
//*************************************************/
class TObjGraf {
// Otros metodos
};
Observaciones:
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 16/24
5/12/2017 Programación Orientada a Objetos en C++
Como hemos incorporado dos nuevos métodos a la clase base TObjGraf (GetAncho() y
GetAlto()) y éstos se han declarado virtuales puros necesitamos instanciarlos en las clases
derivadas:
//*************************************************/
// Definicion de la clase derivada TCirculo.
// Deriva de la clase base TObjGraf
//*************************************************/
int Radio;
public:
// Metodo constructor
};
//*************************************************/
// Definicion de la clase derivada TCuadrado.
// Deriva de la clase base TObjGraf
//*************************************************/
int Lado;
public:
// Metodo constructor
Ahora, añadimos (en ObjGraf.cpp) las funciones write de las propiedades virtuales X e Y:
// Funciones de escritura de las propiedades virtuales X e Y
En este caso, no se puede llamar a los métodos virtuales puros (GetAncho() y GetAlto()) de
las propiedades virtuales (Ancho y Alto) desde el constructor de la clase base TObjGraf.
En ObjGraf.cpp:
TObjGraf :: TObjGraf (TPaintBox *_PaintBox,
TColor _Color, int _X, int _Y)
{
PaintBox = _PaintBox;
FColor = _Color; // MUY IMPORTANTE: Estas tres lineas han cambiado:
FX = _X; // No se puede llamar a los metodos virtuales puros
FY = _Y; // (GetAncho, GetAlto) para fijar el valor de una
// propiedad virtual (Alto, Ancho) desde un
// constructor de la clase base.
}
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 18/24
5/12/2017 Programación Orientada a Objetos en C++
Los objetos gráficos (Cir1, Cir2, Cuad1 y Cuad2) se crean con sus
correspondientes constructores, que en última instancia llaman al constructor de
la clase base para establecer los valores de las propiedades reales FX, FY, FColor y
PaintBox. La consecuencia es que si se crea un círculo, por ejemplo, con
coordenadas incorrectas no se corrigen ya que como el constructor de la clase
base no puede utilizar la propiedad virtual X para escritura no se emplea el
método SetX().
por:
5.7. Polimorfismo
Es demostrar comportamientos distintos según la situación. Puede darse de tres formas
diferentes:
Funciones: sobrecarga.
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 19/24
5/12/2017 Programación Orientada a Objetos en C++
5.7.1.Sobrecarga de funciones.
Ocurre cuando en una clase existen dos métodos con idéntico nombre pero con distinta lista
de parámetros. El compilador los considera como dos métodos distintos y aplicará cada uno
de ellos en la situación apropiada.
En ObjGraf.h:
TObjGraf (TObjGraf *ObjGraf);
En ObjGraf.cpp:
TObjGraf::TObjGraf (TObjGraf *ObjGraf)
{
PaintBox = ObjGraf->PaintBox;
FColor = ObjGraf->Color;
FX = ObjGraf->FX;
FY = ObjGraf->FY;
}
Una clase se puede comportar como cualquiera de sus antecesoras (en la asignación por
ejemplo). Como tenemos variables (punteros) que pueden contener objetos de distintas
clases, el compilador no sabe qué tipo de objeto es al que realmente apunta la variable (en
tiempo de compilación) por lo tanto hay retrasar el enlace a tiempo de ejecución.
Para ilustrar el polimorfismo, crearemos una nueva clase, TPelota, que derive de la clase
TCirculo. Una pelota (un objeto de tipo TPelota, para ser más precisos) es un círculo que
tiene la capacidad de movimiento. Para implementar el movimiento de una pelota
necesitamos incorporar nuevas propiedades y métodos propios a la clase TPelota. Sin
embargo, en este momento nos interesa poner de manifiesto el polimorfismo, lo que
conseguimos a través del método Mostrar() asociado a la clase TPelota. Antes,
modificamos la declaración del método Mostrar() de la clase TCirculo para obligar a sus
descendientes a implementar su propio método Mostrar(): basta con indicar que en el
método Mostrar() de la clase TCirculo es virtual.
En ObjGraf.h:
//*************************************************/
// Definicion de la clase derivada TCirculo.
// Deriva de la clase base TObjGraf
//*************************************************/
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 20/24
5/12/2017 Programación Orientada a Objetos en C++
class TCirculo : public TObjGraf {
private:
...
public:
...
Ahora nos centramos en la nueva clase TPelota. Antes, por comodidad y claridad, definimos
un tipo por enumeración para la dirección del movimiento:
En ObjGraf.h:
// Tipo definido por enumeracion para la direccion de TPelota. Codificacion:
/*
NO N NE
10 2 6
\ | /
O 8 --- * --- 4 E
/ | \
9 1 5
SO S SE
*/
enum TDireccion {S=1, N=2, E=4, O=8, SE=5, NE=6, SO=9, NO=10};
private:
public:
// Constructores
// Otros metodos
/*****************************************************/
// Metodos asociados a la clase derivada TPelota.
// TPelota deriva de la clase TCirculo, que a su
// vez deriva de la clase base TObjGraf
/*****************************************************/
return (_Dir);
}
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 22/24
5/12/2017 Programación Orientada a Objetos en C++
Vamos a crear dinámicamente cuatro objetos de diferentes clases. Estos objetos van a ser
referenciados (mediante punteros) desde un vector de objetos de tipo TObjGraf *. El
polimorfismo se va a manifestar invocando a la función Mostrar() para cada uno de esos
objetos.
que se interpreta como: Objs es un puntero a una zona de memoria que contendrá punteros a
objetos de tipo TObjGraf.
Así, en Ppal.cpp:
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//----------------------------------------------------------------------
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 23/24
5/12/2017 Programación Orientada a Objetos en C++
Página principal
http://elvex.ugr.es/decsai/builder/intro/5.html#CREAC_DEST_OBJETOS 24/24