sábado, 7 de agosto de 2010

UNIDAD 7
ARCHIVOS

7.1 CLASES DE E/S CLASE BASE ABSTRACTA


A menudo en el diseño, se quiere la clase base para presentar sólo una interfaz para sus clases derivadas. Esto es, se puede querer que nadie pueda crear un objeto de la clase base y que ésta sirva únicamente para hacer un upcast hacia ella, y poder tener una interfaz. Se consigue haciendo a la clase abstract (abstracta), poniendo como mínimo una función virtual pura. Se puede reconocer a una función virtual pura porque usa la palabra reservada virtual y es seguida por =0. Si alguien intenta hacer un objeto de una clase abstracta, el compilador lo impide. Esta es una utilidad que fuerza a un diseño en concreto.


Cuando se hereda una clase abstracta, hay que implementar todas las funciones virtuales, o la clase que hereda se convierte en una nueva clase abstracta. Crear una función virtual pura permite poner una función miembro en una interfaz sin forzar a proveer un cuerpo con código sin significado para esa función miembro. Al mismo tiempo, una función virtual fuerza a las clases que la hereden a que implemente una definición para ellas.

La clase base abstracta Stream es compatible con bytes de lectura y escritura. Stream tiene compatibilidad asincrónica. Sus implementaciones predeterminadas definen lecturas y escrituras asincrónicas según sus correspondientes métodos asincrónicos, y viceversa.
Todas las clases que representan secuencias se derivan de la clase Stream. La clase Stream y sus clases derivadas proporcionan una visión genérica de los orígenes de datos y los repositorios, aislando al programador de los detalles específicos del sistema operativo y sus dispositivos subyacentes.

7.2 REALIZAR ENTRADA Y SALIDA DE TEXTO


EN C:
En C un archivo puede ser cualquier cosa, desde un archivo de disco a un terminal o una impresora. Se asocia una secuencia con un archivo específico realizando una operación de apertura, una vez que está abierto, la información puede ser intercambiada entre éste y el programa. El puntero a un archivo es el hilo que unifica el sistema de E/S con buffer. Un puntero a un archivo es un puntero a una información que define varias cosas sobre él, incluyendo el nombre, el estado y la posición actual del archivo. En esencia, el puntero a un archivo identifica un archivo en disco específico y utiliza la secuencia asociada para dirigir el funcionamiento de las funciones de E/S con buffer. Para obtener una variable de tipo puntero a archivo se debe utilizar una sentencia como la siguiente:FILE *punt;

La función fopen() abre una secuencia para que pueda ser utilizada y le asocia a un archivo. Su prototipo es: FILE *fopen(const char *nombre_archivo, const char *modo); Donde nombre_archivo es un puntero a una cadena de caracteres que representan un nombre válido del archivo y puede incluir una especificación de directorio. La cadena que apunta modo determina cómo se abre el archivo.

Los modos son los siguientes:

r: Abre un archivo de texto para lectura.
w: Crea un archivo de texto par escritura
a: Abre un archivo de texto para añadir
r+: Abre un archivo de texto para lectura/escritura
w+: Crea un archivo de texto para lectura/escritura
a+: Añade o crea un archivo de texto para lectura/escritura


La función fclose() cierra una secuencia que fue abierta mediante una llamada a fopen(). Escribe toda la información que todavía se encuentre en el buffer del disco y realiza un cierre formal del archivo a nivel del sistema operativo. También libera el bloque de control de archivo asociado con la secuencia, dejándolo libre para su reutilización. A veces es necesario cerrar algún archivo para poder abrir otro, debido a la existencia de un límite del sistema operativo en cuanto al número de archivos abiertos. Su prototipo es: int fclose(FILE *fp);

La función putc() escribe caracteres en un archivo que haya sido abierto previamente para operaciones de escritura, utilizando la función fopen(). Su prototipo es: int putc(int car, FILE *pf);

La función getc() escribe caracteres en un archivo que haya sido abierto, en modo lectura, mediante fopen(). Su prototipo es: int getc(FILE *pf);La función fputs() escribe la cadena en la secuencia especificada. Su prototipo es: fputs() escribe la cadena en la secuencia especificada. Su prototipo es: int fputs(const char *cad, FILE *pf);La función fgets() lee una cadena de la secuencia especificada hasta que se lee un carácter de salto de línea o hasta que se han leído longitud-1 caracteres.

La función rewind() inicia el indicador de posición al principio del archivo indicado por su argumento. Su prototipo es: rewind() inicia el indicador de posición al principio del archivo indicado por su argumento. Su prototipo es: void rewind(FILE *pf);

Existen otras muchas funciones en la biblioteca estándar de C como pueden ser:

remove(): Borra el archivo especificado.
fflush(): Vacía el contenido de una secuencia de salida.
fread(): Lee tipos de datos que ocupan más de un byte. Permiten la lectura de bloques de cualquier tipo de datos.
fwrite(): Escribe tipos de datos que ocupan más de un byte. Permiten la escritura de bloques de cualquier tipo de datos.
fprintf(): Hace las funciones de printf() sobre un fichero.
fscanf(): Hace las funciones de scanf() sobre un fichero.
feof(): Detecta el final de un fichero.
ferror(): Detecta un error en la lectura/escritura de un fichero.
fclose(): cierra una secuencia que fue abierta mediante una llamada a fopen().
putc(): escribe caracteres en un archivo que haya sido abierto previamente para operaciones de escritura, utilizando la función fopen().
getc(): escribe caracteres en un archivo que haya sido abierto, en modo lectura, mediante fopen(). Su prototipo es:
fputs(): escribe la cadena en la secuencia especificada. Su prototipo es: int fputs(const char *cad, FILE *pf);
fgets(): lee una cadena de la secuencia especificada hasta que se lee un carácter de salto de línea o hasta que se han leído longitud-1 caracteres. Su prototipo es: fgets() lee una cadena de la secuencia especificada hasta que se lee un carácter de salto de línea o hasta que se han leído longitud-1 caracteres. Su prototipo es:int fgets(char *cad, FILE *pf);


EN C++:
Cómo podemos trabajar con un stream simultáneamente en entrada y salida. Para eso usaremos la clase fstream, que al ser derivada de ifstream y ofstream, dispone de todas las funciones necesarias para realizar cualquier operación de entrada o salida.
Hay que tener la precaución de usar la opción ios::trunc de modo que el fichero sea creado si no existe previamente.
#include
using namespace std;

int main() {
char l;
long i, lon;
fstream fich("prueba.dat", ios::in
ios::out ios::trunc ios::binary);

fich << "abracadabra" << lon =" fich.tellg();" i =" 0L;">
fich.seekg(i, ios::beg); fich.get(l); if(l == 'a')
{
fich.seekp(i, ios::beg); fich << 'e';
}
}
cout << "Salida:" << i =" 0L;">
{

fich.get(l); cout <<>

}

cout <<>
cin.get();
return 0;
}

Este programa crea un fichero con una palabra, a continuación lee todo el fichero e cambia todos los caracteres 'a' por 'e'. Finalmente muestra el resultado. Básicamente muestra cómo trabajar con ficheros simultáneamente en entrada y salida.

7.3 LEER Y ESCRIBIR ARCHIVOS

Leer archivos: Ifstream
Proporciona una interfaz para leer datos de archivos como flujos de entrada.

Los objetos de esta clase tratan de mantener internamente un puntero a un objeto filebuf que se pueden obtener llamando a rdbuf miembros.

El archivo que se asocia con la corriente puede ser especificado como un parámetro en el constructor o llamando a los miembros abierta.

Después de todas las operaciones necesarias en un archivo se han realizado, puede ser cerrado (o disociada) llamando a cerrar miembros. Una vez cerrado, el mismo objeto de secuencia de archivo puede ser usado para abrir otro archivo.

El is_open función miembro puede ser usado para determinar si el objeto de secuencia está asociada con un archivo.

Escribir archivos: Ofstream

Proporciona una interfaz para escribir datos en archivos como los flujos de salida.

Los objetos de esta clase de mantener internamente un puntero a un objeto filebuf que se pueden obtener llamando a rdbuf miembros.

El archivo que se asocia con la corriente puede ser especificado como un parámetro en el constructor o llamando a los miembros abierta.

Después de todas las operaciones necesarias en un archivo se han realizado, puede ser cerrado (o disociada) llamando a cerrar miembros. Una vez cerrado, el mismo objeto de secuencia de archivo puede ser usado para abrir otro archivo.

El is_open función miembro puede ser usado para determinar si el objeto de secuencia está asociada con un archivo.

7.4 REALIZAR ENTRADA Y SALIDA BINARIA

Muchos sistemas operativos distinguen entre ficheros de texto y ficheros binarios. Por ejemplo, en MS-DOS, los ficheros de texto sólo permiten almacenar caracteres. En otros sistemas no existe tal distinción, todos los ficheros son binarios. En esencia esto es más correcto, puesto que un fichero de texto es un fichero binario con un rango limitado para los valores que puede almacenar. En general, usaremos ficheros de texto para almacenar información que pueda o deba ser manipulada con un editor de texto. Un ejemplo es un fichero fuente C++.
Los ficheros binarios son más útiles para guardar información cuyos valores no estén limitados. Por ejemplo, para almacenar imágenes, o bases de datos. Un fichero binario permite almacenar estructuras completas, en las que se mezclen datos de cadenas con datos numéricos. En realidad no hay nada que nos impida almacenar cualquier valor en un fichero de texto, el problema surge cuando se almacena el valor que el sistema operativo usa para marcar el fin de fichero en un archivo de texto. En MS-DOS ese valor es 0x1A. Si abrimos un fichero en modo de texto que contenga un dato con ese valor, no nos será posible leer ningún dato a partir de esa posición. Si lo abrimos en modo binario, ese problema no existirá. Los ficheros que hemos usado en los ejemplos anteriores son en modo texto, veremos ahora un ejemplo en modo binario:

#include
#include
struct tipoRegistro {
char nombre[32];
int edad;
float altura;
};

int main() {
tipoRegistro pepe;
tipoRegistro pepe2;
ofstream fsalida("prueba.dat",
ios::out ios::binary);

strcpy(pepe.nombre, "Jose Luis");
pepe.edad = 32;
pepe.altura = 1.78;

fsalida.write(reinterpret_cast(&pepe),
sizeof(tipoRegistro));
fsalida.close();

ifstream fentrada("prueba.dat",
ios::in ios::binary);

fentrada.read(reinterpret_cast(&pepe2),
sizeof(tipoRegistro));
cout <<>fentrada.close();

cin.get();
return 0;
}

Al declarar streams de las clases ofstream o ifstream y abrirlos en modo binario, tenemos que añadir el valor ios::out e ios::in, respectivamente, al valor ios::binary. Esto es necesario porque los valores por defecto para el modo son ios::out e ios:in, también respectivamente, pero al añadir el flag ios::binary, el valor por defecto no se tiene en cuenta.


Cuando trabajemos con streams binarios usaremos las funciones write y read. En este caso nos permiten escribir y leer estructuras completas.


En general, cuando usemos estas funciones necesitaremos hacer un casting, es recomendable usar el operador "reinterpret_cast".


BIBLIOGRAFIA
http://www.tutoriales.itsa.edu.mx/programacion1/index.php?mod=clasesdees&ban=0











UNIDAD 6
POLIMORFISMO

6.1 CONCEPTO DE POLIMORFISMO


Permite al programador generar componentes reutilizables de alto nivel que puedan adaptarse a diferentes aplicaciones mediante el cambio de sus partes de bajo nivel.


En programación orientada a objetos se denomina polimorfismo a la capacidad del código de un programa para ser utilizado con diferentes tipos de datos u objetos. También se puede aplicar a la propiedad que poseen algunas operaciones de tener un comportamiento diferente dependiendo del objeto (o tipo de dato) sobre el que se aplican.


El concepto de polimorfismo se puede aplicar tanto a funciones como a tipos de datos. Así nacen los conceptos de funciones polimórficas y tipos polimórficos. Las primeras son aquellas funciones que pueden evaluarse o ser aplicadas a diferentes tipos de datos de forma indistinta; los tipos polimórficos, por su parte, son aquellos tipos de datos que contienen al menos un elemento cuyo tipo no está especificado.


Se puede clasificar el polimorfismo en dos grandes clases:


Polimorfismo dinámico: (o polimorfismo ad hoc) es aquél en el que el código no incluye ningún tipo de especificación sobre el tipo de datos sobre el que se trabaja. Así, puede ser utilizado a todo tipo de datos compatible.


•Polimorfismo estático: (o polimorfismo paramétrico) es aquél en el que los tipos a los que se aplica el polimorfismo deben ser explicitados y declarados uno por uno antes de poder ser utilizados. El polimorfismo dinámico unido a la herencia es lo que en ocasiones se conoce como programación genérica.


También se clasifica en herencia por redefinición de métodos abstractos y por método sobrecargado. El segundo hace referencia al mismo método con diferentes


6.2 CLASE BASE ABSTRACTA
En C++ es posible definir clases abstractas. Una clase abstracta, o clase base abstracta (ABC), es una que está diseñada sólo como clase padre de las cuales se deben derivar clases hijas. Una clase abstracta se usa para representar aquellas entidades o métodos que después se implementarán en las clases derivadas, pero la clase abstracta en sí no contiene ninguna implementación solamente representa los métodos que se deben implementar. Por ello, no es posible instanciar una clase abstracta, pero sí una clase concreta que implemente los métodos definidos en ella.


Las clases abstractas son útiles para definir interfaces, es decir, un conjunto de métodos que definen el comportamiento de un módulo determinado. Estas definiciones pueden utilizarse sin tener en cuenta la implementación que se hará de ellos.


En C++ los métodos de las clases abstractas se definen como funciones virtuales puras:

class Abstracta
{
public:
virtual int metodo() = 0;
};

class ConcretaA : public Abstracta
{

6.3 SUBPROGRAMAS VIRTUALES


Las funciones virtuales permiten que clases derivadas de una misma base (clases hermanas) puedan tener diferentes versiones de un método. Se utiliza la palabra-clave virtual para avisar al compilador que un método será polimórfico y que en las clases derivadas existen distintas definiciones del mismo.


Para declarar que un método de una clase base es virtual, su prototipo se declara como siempre, pero anteponiendo la palabra-clave virtual, que indica al compilador algo así como: "Será definido más tarde en una clase derivada". Ejemplo:
Sintaxis: virtual void dibujar();

Una función virtual o método virtual es una función cuyo comportamiento, al ser declarado "virtual", es determinado por la definición de una función con la misma cabecera en alguna de sus subclases. Este concepto es una parte muy importante del polimorfismo en la POO.


El concepto de función virtual soluciona los siguientes problemas:
En POO, cuando una clase derivada hereda de una clase base, un objeto de la clase derivada puede ser referido tanto como del tipo de la clase base como del tipo de la clase derivada. Si hay funciones de la clase base redefinidas por la clase derivada, aparece un problema cuando un objeto derivado ha sido cohercionado como del tipo de la clase base. Cuando un objeto derivado es referido como del tipo de la base, el comportamiento de la llamada a la función deseado es ambiguo.


Distinguir entre virtual y no virtual sirve para resolver este problema. Si la función en cuestión es designada "virtual", se llamará a la función de la clase derivada (si existe). Si no es virtual, se llamará a la función de la clase base.


6.4 DESTRUCTORES VIRTUALES


Como cualquier otra función miembro, los destructores pueden ser declarados virtuales. El destructor de una clase derivada de otra cuyo destructor es virtual, también es virtual.

La existencia de un destructor virtual permite que un objeto de una subclase pueda ser correctamente destruido por un puntero a su clase-base.

Ejemplo:
class B { // Superclase (polimórfica)
...
virtual ~B(); // Destructor virtual
};

class D : public B { // Subclase (deriva de B)
...
~D(); // destructor también virtual
};

void func() {
B* ptr = new D; // puntero a superclase asignado a objeto de subclase
delete ptr; // Ok: delete es necesario siempre que se usa new
}

En el ejemplo anterior el mecanismo de llamada de las funciones virtuales permite que el operador delete invoque al destructor correcto, es decir, al destructor ~D de la subclase, aunque se invoque mediante el puntero ptr a la superclase B*. Si el destructor no hubiese sido virtual no se hubiese invocado el destructor derivado ~D, sino el de la superclase ~B, dando lugar a que los miembros privativos de la subclase no hubiesen sido desasignados. Tendríamos aquí un caso típico de "misteriosas" pérdidas de memoria, tan frecuentes en los programas C++ como difíciles de depurar.



BIBLIOGRAFIA
http://www.tutoriales.itsa.edu.mx/programacion1/index.php?mod=concpolimorfismo&ban=0

UNIDAD 5 HERENCIA
5.1 IMPORTANCIA DE LA HERENCIA EN LA POO

La herencia es la última de las propiedades relativas a la OOP, Consiste en la propagación de los atributos y las operaciones a través de distintas sub-clases definidas a partir de una clase común.
Introduce, por tanto, una posibilidad de refinamiento sucesivo del concepto de clase. Nos permite definir una clase principal y , a través de sucesivas aproximaciones, cualquier característica de los objetos. A partir de ahora definiremos como sub-clases todas aquellas clases obtenidas mediante refinamiento de una (o varias) clases principales.
La herencia nos permite crear estructuras jerárquicas de clases donde es posible la creación de sub-clases que incluyan nuevas propiedades y atributos. Estas sub-clases admiten la definición de nuevos atributos, así como crear, modificar o inhabilitar propiedades.
Para pensarlo de manera más fácil podemos abstraernos al siguiente ejemplo:
Pensemos en los distintos sub-modelo s asociados a un modelo básico de automóvil. A partir de este modelo básico, los fabricantes introducen distintas características (aire acondicionado, ABS, distintas tapicerías, acabados, etc.) que crean sub - clases. Todas estas sub-clases tienen en común la estructura básica (chasis, dirección, etc.) u varían sólo en algunos de sus componentes.
Asociemos a este tipo básico una clase cuyos atributos representen las piezas que componen el coche. Las sub-clases aportarán sus propios atributos (en el caso de vehículos con aire acondicionado, todos aquellas piezas que lo componen), permitiendo la definición de todos los posibles modelos.


Además, es posible que una sub-clase herede atributos y propiedades de más de una clase. Este proceso se denomina herencia múltiple y lo veremos con más detalle en capítulos posteriores.
La herencia es, sin duda alguna, una de las propiedades más importantes de la OOP, ya que permite, a través de la definición de una clase básica, ir añadiendo propiedades a medida que sean necesarias y, además, en el sub-conjunto de objetos que sea preciso.

La herencia permite que los objetos pueden compartir datos y comportamientos a través de las diferentes sub-clases, sin incurrir en redundancia. Más importante que el ahorro de código, es la claridad que aporta al identificar que las distintas operaciones sobre los objetos son en realidad una misma cosa.

La herencia es una propiedad esencial de la Programación Orientada a Objetos que consiste en la creación de nuevas clases a partir de otras ya existentes. Este término ha sido prestado de la Biología donde afirmamos que un niño tiene la cara de su padre, que ha heredado ciertas facetas físicas o del comportamiento de sus progenitores.
La herencia es la característica fundamental que distingue un lenguaje orientado a objetos, como el C++ o Java, de otro convencional como C, BASIC, etc. Java permite heredar a las clases características y conductas de una o varias clases denominadas base. Las clases que heredan de clases base se denominan derivadas, estas a su vez pueden ser clases bases para otras clases derivadas. Se establece así una clasificación jerárquica, similar a la existente en Biología con los animales y las plantas.

La herencia ofrece una ventaja importante, permite la reutilización del código. Una vez que una clase ha sido depurada y probada, el código fuente de dicha clase no necesita modificarse. Su funcionalidad se puede cambiar derivando una nueva clase que herede la funcionalidad de la clase base y le añada otros comportamientos. Reutilizando el código existente, el programador ahorra tiempo y dinero, ya que solamente tiene que verificar la nueva conducta que proporciona la clase derivada.


La herencia es la última de las propiedades relativas a la OOP, Consiste en la propagación de los atributos y las operaciones a través de distintas sub-clases definidas a partir de una clase común.
Introduce, por tanto, una posibilidad de refinamiento sucesivo del concepto de clase. Nos permite definir una clase principal y , a través de sucesivas aproximaciones, cualquier característica de los objetos. A partir de ahora definiremos como sub-clases todas aquellas clases obtenidas mediante refinamiento de una (o varias) clases principales.

La herencia nos permite crear estructuras jerárquicas de clases donde es posible la creación de sub-clases que incluyan nuevas propiedades y atributos. Estas sub-clases admiten la definición de nuevos atributos, así como crear, modificar o inhabilitar propiedades.

Para pensarlo de manera más fácil podemos abstraernos al siguiente ejemplo:
Pensemos en los distintos sub-modelo s asociados a un modelo básico de automóvil. A partir de este modelo básico, los fabricantes introducen distintas características (aire acondicionado, ABS, distintas tapicerías, acabados, etc.) que crean sub - clases. Todas estas sub-clases tienen en común la estructura básica (chasis, dirección, etc.) u varían sólo en algunos de sus componentes.
Asociemos a este tipo básico una clase cuyos atributos representen las piezas que componen el coche. Las sub-clases aportarán sus propios atributos (en el caso de vehículos con aire acondicionado, todos aquellas piezas que lo componen), permitiendo la definición de todos los posibles modelos.


Además, es posible que una sub-clase herede atributos y propiedades de más de una clase. Este proceso se denomina herencia múltiple y lo veremos con más detalle en capítulos posteriores.
La herencia es, sin duda alguna, una de las propiedades más importantes de la OOP, ya que permite, a través de la definición de una clase básica, ir añadiendo propiedades a medida que sean necesarias y, además, en el sub-conjunto de objetos que sea preciso.

La herencia permite que los objetos pueden compartir datos y comportamientos a través de las diferentes sub-clases, sin incurrir en redundancia. Más importante que el ahorro de código, es la claridad que aporta al identificar que las distintas operaciones sobre los objetos son en realidad una misma cosa.
La herencia es una propiedad esencial de la Programación Orientada a Objetos que consiste en la creación de nuevas clases a partir de otras ya existentes. Este término ha sido prestado de la Biología donde afirmamos que un niño tiene la cara de su padre, que ha heredado ciertas facetas físicas o del comportamiento de sus progenitores.

La herencia es la característica fundamental que distingue un lenguaje orientado a objetos, como el C++ o Java, de otro convencional como C, BASIC, etc. Java permite heredar a las clases características y conductas de una o varias clases denominadas base. Las clases que heredan de clases base se denominan derivadas, estas a su vez pueden ser clases bases para otras clases derivadas. Se establece así una clasificación jerárquica, similar a la existente en Biología con los animales y las plantas.
La herencia ofrece una ventaja importante, permite la reutilización del código. Una vez que una clase ha sido depurada y probada, el código fuente de dicha clase no necesita modificarse. Su funcionalidad se puede cambiar derivando una nueva clase que herede la funcionalidad de la clase base y le añada otros comportamientos. Reutilizando el código existente, el programador ahorra tiempo y dinero, ya que solamente tiene que verificar la nueva conducta que proporciona la clase derivada.


5.2 JERARQUIA DE HERENCIA


La Jerarquía es una propiedad que permite la ordenación de las abstracciones.
Las dos jerarquías más importantes de un sistema complejo son:
• Estructura de clases (jerarquía “es-un” (is-a): generalización/especialización).
• Estructura de objetos (jerarquía “parte-de” (part-of): agregación).


Las jerarquías de generalización/especialización se conocen como herencia. Básicamente, la herencia define una relación entre clases, en donde una clase comparte la estructura o comportamiento definido en una o más clases (herencia simple y herencia múltiple, respectivamente).
La agregación es el co

ncepto que permite el agrupamiento físico de estructuras relacionadas lógicamente. Así, un camión se compone de ruedas, motor, sistema de transmisión y chasis; en consecuencia, camión es una agregación, y ruedas, motor, transmisión y chasis son agregados de camión

Las jerarquías de herencia son más fáciles de implementar que de diseñar, por lo que es arriesgado comenzar a codificar antes de identificar claramente las necesidades. La corrección de errores de diseño en una jerarquía de clases tras la implementación puede requerir cambios que deshabilitan las aplicaciones existentes. En esta sección se explican consideraciones del diseño de jerarquía de herencia y se proporciona información que ayuda a evitar estos errores.



5.2.1 CONCEPTOS DE HERENCIA SIMPLE Y MULTIPLE

Herencia Simple
En C++ es un mecanismo de abstracción creado para poder facilitar y mejorar el diseño de las clases de un programa. Con ella se pueden crear nuevas clases a partir de clases ya hechas, siempre y cuando tengan un tipo de relación especial.

En la herencia, las clases derivadas "heredan" los datos y las funciones miembro de las clases base, pudiendo las clases derivadas redefinir estos comportamientos (polimorfismo) y añadir comportamientos nuevos propios de las clases derivadas. Para no romper el principio de encapsulamiento (ocultar datos cuyo conocimiento no es necesario para el uso de las clases), se proporciona un nuevo modo de visibilidad de los datos/funciones: "protected". Cualquier cosa que tenga visibilidad protected se comportará como pública en la clase Base y en las que componen la jerarquía de herencia, y como privada en las clases que NO sean de la jerarquía de la herencia.

Antes de utilizar la herencia, nos tenemos que hacer una pregunta, y si tiene sentido, podemos intentar usar esta jerarquía:
Si la frase ES-UN tiene sentido, entonces estamos ante un posible caso de herencia donde clase A será la clase base y clase B la derivada.
Ejemplo: clases Barco, Acorazado, Carguero, etc. un Acorazado ES-UN Barco, un Carguero ES-UN Barco, un Trasatlántico ES-UN Barco, etc.

En este ejemplo tendríamos las cosas generales de un Barco (en C++)
class Barco
{
protected:
char* nombre;
float peso;
public:
//Constructores y demás funciones básicas de barco
};

y ahora las características de las clases derivadas, podrían (a la vez que heredan las de barco) añadir cosas propias del subtipo de barco que vamos a crear, por ejemplo:


class Carguero: public Barco { // Esta es la manera de especificar que hereda de Barco
private:
float carga;
//El resto de cosas
};

class Acorazado: public Barco {
private:
int numeroArmas;
int Soldados;
// Elresto de cosas
};

Por último, hay que mencionar que existen 3 clases de herencia que se diferencian en el modo de manejar la visibilidad de los componentes de la clase resultante:
Herencia pública (class Derivada: public Base ) : Con este tipo de herencia se respetan los comportamientos originales de las visibilidades de la clase Base en la clase Derivada.
• Herencia privada (clase Derivada: private Base) : Con este tipo de herencia todo componente de la clase Base, será privado en la clase Derivada (ojo! siempre será privado aunque ese dato fuese público en la clase Base)
Herencia protegida (clase Derivada: protected Base) : Con este tipo de herencia, todo componente público y protegido de la clase Base, será protegido en la clase Derivada, y los componentes privados, siguen siendo privados.

Herencia Multiple


Es el mecanismo que permite al programador hacer clases derivadas a partir, no de una sola clase base, sino de varias. Para entender esto mejor, pongamos un ejemplo: Cuando ves a quien te atiende en una tienda, como persona que es, podrás suponer que puede hablar, comer, andar, pero, por otro lado, como empleado que es, también podrás suponer que tiene un jefe, que puede cobrarte dinero por la compra, que puede devolverte el cambio, etc.
Si esto lo trasladamos a la programación sería herencia múltiple (clase empleado_tienda):
class Persona {
...
Hablar();
Caminar();
...
};

class Empleado {
Persona jefe;
int sueldo;
Cobrar();
...
};

class empleado_tienda: public Persona, Empleado {
...
AlmacenarStock();
ComprobarExistencias();
...
};
Por tanto, es posible utilizar más de una clase para que otra herede sus características.


5.2.2 PRINCIPIOS GENERALES DE DISEÑO DE JERARQUIAS

Incluso las jerarquías de clases bien diseñadas necesitan evolucionar con el tiempo. Las opciones iniciales que elija en el momento de diseñar una jerarquía de clases pueden simplificar su trabajo posteriormente.
Extender jerarquías de clases
En la siguiente lista se incluyen sugerencias para simplificar la extensión de las jerarquías de clases:
• Las jerarquías se definen desde lo general a lo específico. Defina las clases en cada nivel de una jerarquía de herencia de la forma más genérica posible. Las clases derivadas pueden heredar, reutilizar y extender métodos de clases base.
Por ejemplo, suponga que está diseñando una jerarquía de clases que modela el hardware del equipo. Al comenzar a modelar los dispositivos de salida, podría definir clases denominadas Display, Printer y File. Después podría definir las clases que implementan los métodos definidos en las clases base. Por ejemplo, la clase LCD Display? puede haber derivado de Display e implementar un método denominado Enter Power Save Mode?.
• Defina los tipos de datos y el almacenamiento con generosidad a fin de evitar cambios difíciles posteriormente. Por ejemplo, podría considerar el uso de una variable de tipo Long aunque los datos actuales sólo requieran una variable estándar Integer.
• Exponga sólo los elementos que las clases derivadas necesiten. Los campos y métodos Private reducen los conflictos de denominación y protegen a otros usuarios del uso de elementos que pueden necesitar cambios posteriormente.
• Los miembros que sólo sean necesarios para las clases derivadas deben marcarse como Protected. Esto garantiza que sólo las clases derivadas dependen de estos miembros y facilita la actualización de estos miembros durante el desarrollo.
• Asegúrese de que los métodos de clase base no dependen de miembros Overridable cuya funcionalidad pueden cambiar las clases herederas. Existen dos tipos de jerarquizar: La primera consiste en derivar una clase de otra, es el caso mas habitual y se llama “Herencia”. La otra consiste en encapsular un objeto como miembro de otro, a esta se le llama “Encapsulamiento”.
La unica regla que tenemos que tener en mente es: Si un objeto se relaciona con otro de la forma “es un” hay que usar la herencia publica. Si por el contrario la relacion se describe mejor de la forma “tiene un” hay que usar el encapsulamiento.
Una forma sencilla de ver la diferencia entre los dos tipos es con este ejemplo:
• La clase C Mercedes? “es un” tipo de la clase C Car?
• La clase C Mercedes “tiene un” tipo de case C Volante?

5.2.3 ESPECIFICADORES DE ACCESO A JERARQUIA DE CLASES

Creamos un objeto c de la clase Círculo situado en el punto (0, 0) y de 5.5 unidades de radio. Calculamos y mostramos el valor de su área:
Circulo c=new Circulo(0, 0, 5.5);
System.out.println("Area del círculo "+c.area());
Creamos un objeto r de la clase Rectangulo situado en el punto (0, 0) y de dimensiones 5.5 de anchura y 2 unidades de largo. Calculamos y mostramos el valor de su área:
Rectangulo r=new Rectangulo(0, 0, 5.5, 2.0);
System.out.println("Area del rectángulo "+r.area());
Veamos ahora, una forma alternativa, guardamos el valor devuelto por new al crear objetos de las clases derivadas en una variable f del tipo Figura (clase base):
Figura f=new Circulo(0, 0, 5.5);
System.out.println("Area del círculo "+f.area());
f=new Rectangulo(0, 0, 5.5, 2.0);
System.out.println("Area del rectángulo "+f.area());


5.3 DEFINICION DE UNA CLASE BASE

Los programadores crean clases base:


1. Cuando se dan cuenta que diversos tipos tienen algo en común, por ejemplo en el juego del ajedrez peones, alfiles, rey, reina, caballos y torres, son piezas del juego. Creamos, por tanto, una clase base y derivamos cada pieza individual a partir de dicha clase base.

2. Cuando se precisa ampliar la funcionalidad de un programa sin tener que modificar el código existente.

Ejemplo que simule la utilización de librerías de clases para crear un interfaz gráfico de usuario como Windows 3.1 o Windows 95.

Supongamos que tenemos una clase que describe la conducta de una ventana muy simple, aquella que no dispone de título en la parte superior, por tanto no puede desplazarse, pero si cambiar de tamaño actuando con el ratón en los bordes derecho e inferior.
La clase Ventana tendrá los siguientes miembros dato: la posición x e y de la ventana, de su esquina superior izquierda y las dimensiones de la ventana: ancho y alto.
public class Ventana {
protected int x;
protected int y;
protected int ancho;
protected int alto;
public Ventana(int x, int y, int ancho, int alto) {
this.x=x;
this.y=y;
this.ancho=ancho;
this.alto=alto;
}
//...
}


5.4 DEFINICION DE UNA CLASE DERIVADA

Incrementamos la funcionalidad de la clase Ventana definiendo una clase derivada denominada VentanaTitulo. Los objetos de dicha clase tendrán todas las características de los objetos de la clase base, pero además tendrán un título, y se podran desplazar (se simula el desplazamiento de una ventana con el ratón).



La clase derivada heredará los miembros dato de la clase base y las funciones miembro, y tendrá un miembro dato más, el título de la ventana.
public class VentanaTitulo extends Ventana{
protected String titulo;
public VentanaTitulo(int x, int y, int w, int h, String nombre) {
super(x, y, w, h);
titulo=nombre;
}
extends es la palabra reservada que indica que la clase VentanaTitulo deriva, o es una subclase, de la clase Ventana.
La primera sentencia del constructor de la clase derivada es una llamada al constructor de la clase base mediante la palabra reservada super. La llamada
super(x, y, w, h);
Inicializa los cuatro miembros dato de la clase base Ventana: x, y, ancho, alto. A continuación, se inicializa los miembros dato de la clase derivada, y se realizan las tareas de inicialización que sean necesarias. Si no se llama explícitamente al constructor de la clase base Java lo realiza por nosotros, llamando al constructor por defecto si existe.
La función miembro denominada desplazar cambia la posición de la ventana, añadiéndoles el desplazamiento.

public void desplazar(int dx, int dy){
x+=dx;
y+=dy;
}
Redefine la función miembro mostrar para mostrar una ventana con un título:
public void mostrar(){
super.mostrar();
System.out.println("titulo : "+titulo);
}

En la clase derivada se define una función que tiene el mismo nombre y los mismos parámetros que la de la clase base. Se dice que redefinimos la función mostrar en la clase derivada. La función miembro mostrar de la clase derivada VentanaTitulo hace una llamada a la función mostrar de la clase base Ventana, mediante
super.mostrar();
De este modo aprovechamos el código ya escrito, y le añadimos el código que describe la nueva funcionalidad de la ventana por ejemplo, que muestre el título.
Si nos olvidamos de poner la palabra reservada super llamando a la función mostrar, tendríamos una función recursiva. La función mostrar llamaría a mostrar indefinidamente.
public void mostrar(){ //¡ojo!, función recursiva
System.out.println("titulo : "+titulo);
mostrar();
}
La definición de la clase derivada VentanaTitulo, será la siguiente:
package ventana;
public class VentanaTitulo extends Ventana{
protected String titulo;
public VentanaTitulo(int x, int y, int w, int h, String nombre) {
super(x, y, w, h);
titulo=nombre;
}
public void mostrar(){
super.mostrar();
System.out.println("titulo : "+titulo);
}
public void desplazar(int dx, int dy){
x+=dx;
y+=dy;
}
}

C++ utiliza un sistema de herencia jerárquica. Es decir, se hereda una clase de otra, creando nuevas clases a partir de las clases ya existentes. Sólo se pueden heredar clases, no funciones ordinarias n variables, en C++. Una clase derivada hereda todos los miembros dato excepto, miembros dato estático, de cada una de sus clases base. Una clase derivada hereda la función miembro de su clase base. Esto significa que se hereda la capacidad para llamar a funciones miembro de la clase base en los objetos de la clase derivada.




5.4.1 CONSTRUCTORES Y DESTRUCTORES DE CLASES DERIVADAS

Constructores en clases derivadas
Al instanciar objetos de clases derivadas se inicia una cadena de invocaciones a constructores en las cuales el constructor de la clase derivada, antes de realizar sus propias tareas, invoca (ya sea implícita o explícitamente) al constructor de su clase base. Similarmente, si la clase base fue derivada de otra clase, el constructor de la clase base debe invocar al constructor de la clase ubicada en el siguiente nivel superior de la jerarquía, y así sucesivamente. El último constructor invocado en la cadena es el constructor de la clase Object, cuyo cuerpo se ejecuta primero. El cuerpo del constructor de la clase derivada se ejecuta al final. El constructor de cada clase base inicializa las variables de instancia que el objeto de la clase derivada hereda.
Destructores en clases derivadas
Cuando remueve de la memoria un objeto de una clase derivada, el recolector de basura invoca al destructor del objeto. Esto inicia una cadena de invocaciones a destructores, en donde el destructor de la clase derivada y los destructores de las clases bases directas e indirectas se ejecutan en orden inverso al que se ejecutaron los constructores, esto es, primero se ejecuta el destructor de la clase derivada y al final se ejecuta el destructor de la clase base ubicada en el nivel superior de la jerarquía. La ejecución de los destructores debe liberar todos los recursos que el objeto adquirió, antes de que el recolector de basura reclame la memoria de ese objeto. Cuando el recolector de basura invoca al destructor de un objeto de una clase derivada, ese destructor realiza su tarea y después invoca al destructor de la clase base. El proceso se repite hasta que se invoca al destructor de la clase Object.


Ejemplo:
// Destruct Derivadas?.cs :
Destructores en clases derivadas. using C = System.Console;
class Animal { ~ Animal( )
{ C.Write Line?(“Muere mi parte Animal …”); } }
class Mamífero : Animal { ~ Mamífero( )
{ C.Write Line(“Muere mi parte Mamífero …”); } }
class Perro : Mamífero { ~ Perro( )
{ C.Write Line(“Muere mi parte Perro …”); } }
public class Principal { static void Main( ) { Perro Fido = new Perro ( ); } }


5.4.2 CONVERSION IMPLICITA DE OBJ. DE CLASE DERIBADA A OBJ. DE CLASE BASE

La programación orientada a objetos extiende los tipos abstractos de datos permitiendo relaciones tipo-subtipo. Esto es alcanzado a través de un mecanismo denominado herencia. Más que reimplementar características compartidas, una clase puede heredar datos y funciones miembros de otras clases. En C++, este mecanismo es implementado a través de la derivación de clases.
Especificación de derivación
Veamos el siguiente ejemplo:



// clases que sirven como clases base
class Animal{...};
class EnExtincion{...};
class Carnivoro{...};
class Herbivoro{...};
// Derivación simple
class Oso:public Animal { ...};

// Derivaciones múltiples
class Gato : public Animal, Carnivoro {...};
class Panda : private EnExtincion, public Oso, private Herbivoro {...};

Si se omite un atributo de público,privado o protegido a la clase base, esta es manipulada como privada. En el caso de la clase gato, Carnivoro es una clase base privada.
Una clase derivada puede servir como clase base para subsecuentes derivaciones.

La sintaxis para definir clases bases es igual a definir clases ordinarias, con las siguientes dos excepciones:
• Miembros que se quiere sean heredados por clases derivadas, pero no públicos son declarados miembros protegidos.
• Funciones miembro cuya implementación depende de detalles de representación de subsecuentes derivaciones y que son desconocidas al tiempo del diseño de la clase base son declaradas como funciones virtuales.
El acceso desde clases derivadas a miembros heredados es como si fueran miembros propios (depende del tipo de herencia realizada). Tambien puede usarse el class scope operator es decir, para acceder al miembro A de la clase ClassA desde el objeto Obj de la clase ClassB sería Obj.ClassA::A o bien Obj.A.
Existen dos casos que requieren el uso de la notación extendida:
• Cuando el nombre del miembro heredado es reusado.
• Cuando 2 o más clases bases definen un miembro heredado con el mismo nombre.
class ObjetoGrafico
{
protected:
int Visible;
int X,Y;
public:
ObjetoGrafico(int A, int B): X(A), Y(B), Visible(0){};
virtual void Draw() = 0;
virtual void Hide() = 0;
virtual ~ObjetoGrafico(){}
};
class Circulo: public ObjetoGrafico
{
private:
int Radio;
public:
Circulo(int A, int B, int R):ObjetoGrafico(A,B), Radio(R){};
void Draw(){...};
void Hide(){...};
~ObjetoGrafico(){Hide();}
};
class CirduloLleno: public Circulo
{
private:
int Patron;
public:
CirculoLleno(int A, int B, int R, int P):Circulo(A,B,R), Patron(P){...}
void Draw(){Circulo::Draw();...};
void Hide(){...};
};


Clases bases públicas y derivadas


Los miembros heredados de una clase base pública mantienen su nivel de acceso dentro de la clase derivada. En general, en una jerarquía de derivación pública, cada clase derivada subsecuentemente tiene acceso combinado a miembros públicos y protegidos de las clases bases previas en una rama.
Los miembros públicos y protegidos heredados a través de una derivación protegida, se vuelen miembros protegidos de la clase derivada.


Los miembros públicos y protegidos heredados a traves de una derivación privada se vuelven miembros privados de la clase derivada. Esto lleva a:


• Los miembros públicos de una clase base no pueden ser accedidos a través de un objeto de una clase derivada.
• Los miembros públicos y protegidos de la clase base ya no seran más visibles en subsecuentes derivaciones.
Conversiones estándar bajo derivación
Existen 4 conversiones predefinidas que son aplicables entre una clase derivada y su clase base pública:
• Un objeto de la clase derivada se convierte en forma implícita en un objeto de la clase base pública.
• Una referencia a una clase derivada se convierte implícitamente en una referencia a la clase base pública.
• Un puntero a la clase derivada se convertirá implícitamente en un puntero a la clase base.
• Un puntero a un miembro de una clase base se convertirá en forma implícita en un puntero a miembro de la clase derivada.




5.5 HERENCIA MULTIPLE

Es una propiedad que permite que los objetos sean creados a partir de otros ya existentes, obteniendo características (métodos y atributos) similares a los ya existentes. Es la relación entre una clase general y otra clase más específica. Es un mecanismo que nos permite crear clases derivadas a partir de clase base, nos permite compartir automáticamente métodos y datos entre clases, subclases y objetos.
Por ejemplo: Si declaramos una clase párrafo derivada de una clase texto, todos los métodos y variables asociadas con la clase texto, son automáticamente heredados por la subclase párrafo.
La herencia múltiple es uno de los mecanismos de la programación orientada a objetos, por medio del cual una clase se deriva de otra, llamada entonces superclase, de manera que extiende su funcionalidad. Una de sus funciones más importantes es la de proveer Polimorfismo y late binding.
La idea es la de partir de las situaciones más generales e ir derivando hacia las más particulares, creando categorías, de la misma forma en que piensa el ser humano.
Ventajas:
• Ayuda a los programadores ahorrar código y tiempo, ya que si tiene una clase lista es solo de implementarla y listo todo el código de esta se resume a solo un llamado.
• Los objetos pueden ser construidos a partir de otros similares. Para ello es necesario que exista una clase base y una jerarquía (relacionamiento) de clases.
• La clase derivada puede heredar código y datos de la clase base, añadiendo código o modificando lo heredado.
• Las clases que heredan propiedades de otra clase pueden servir como clase base de otras.



BIBLIOGRAFIA

http://www.tutoriales.itsa.edu.mx/programacion1/index.php?mod=importancia&ban=0





UNIDAD 5.

HERENCIA

La herencia es la última de las propiedades relativas a la OOP, Consiste en la propagación de los atributos y las operaciones a través de distintas sub-clases definidas a partir de una clase común.
Introduce, por tanto, una posibilidad de refinamiento sucesivo del concepto de clase. Nos permite definir una clase principal y , a través de sucesivas aproximaciones, cualquier característica de los objetos. A partir de ahora definiremos como sub-clases todas aquellas clases obtenidas mediante refinamiento de una (o varias) clases principales.

La herencia nos permite crear estructuras jerárquicas de clases donde es posible la creación de sub-clases que incluyan nuevas propiedades y atributos. Estas sub-clases admiten la definición de nuevos atributos, así como crear, modificar o inhabilitar propiedades.
Para pensarlo de manera más fácil podemos abstraernos al siguiente ejemplo:
Pensemos en los distintos sub-modelo s asociados a un modelo básico de automóvil.


A partir de este modelo básico, los fabricantes introducen distintas características (aire acondicionado, ABS, distintas tapicerías, acabados, etc.) que crean sub - clases. Todas estas sub-clases tienen en común la estructura básica (chasis, dirección, etc.) u varían sólo en algunos de sus componentes.

Asociemos a este tipo básico una clase cuyos atributos representen las piezas que componen el coche. Las sub-clases aportarán sus propios atributos (en el caso de vehículos con aire acondicionado, todos aquellas piezas que lo componen), permitiendo la definición de todos los posibles modelos.