sábado, 9 de enero de 2016

Plantillas de clases


Es posible comprender qué es una pilla (una estructura de datos en la que insertamos elementos en un orden y los recuperamos en el orden último en salir, primero en entrar) independientemente del tipo de elementos que se coloquen en ella. Pero cuando en realidad se trata de crear la instancia de una pila, debemos especificar un tipo de dato. Esto crea una maravillosa oportunidad para la reutilización del software. Necesitamos los medios para describir la noción de una pila de manera genérica y crear las instancias a partir de las clases, que son versiones específicas de esta clase genérica. En C++, esta capacidad la proporcionan las plantillas de clases.







Polimorfismo

Se denomina polimorfismo a la capacidad que tienen los objetos ded una clase de responder al mismo mensaje o evento en función de los parámetros utilizados durante su innovación. Un objeto polimórfico es una entidad que puede contener valores de diferentes tipos durante la ejecución del programa.
Nos permite escribir programas que procesen objetos de clases que formen parte de la misma jerarquía de clases, como si todos fueran objetos de la clase base de la jerarquía.

El polimorfismo trabaja con los manejos de las referencias de clases base, pero no con los de nombres.





Niveles de herencia

Dependiendo del número de clases y de cómo se relacionan la herencia puede ser simple, múltiple y de niveles múltiples
Herencia Simple
Cuando sólo se tiene una clase base de la cual se hereda la clase derivada, la herencia simple no excluye la posibilidad de que una misma clase se pueda derivar más una clase derivada.
Herencia múltiple
En el tipo de herencia múltiple se usan dos o más clases base para derivar una clase. Es decir, la clase derivada comparte los atributos y métodos de más de una clase.
Herencia de niveles múltiples

La herencia de niveles múltiples se presenta cuando una clase derivada se usa como base para definir otra clase derivada.

Herencia: Clases base y clases derivadas

A menudo  un objeto de una clase en realidad también “es un” objeto de otra clase. Ciertamente un rectángulo es un cuadrilátero. Así, se puede decir que la clase Rectángulo hereda de la clase Cuadrilátero. En este contexto, a la clase cuadrilátero se le llama clase base y a la clase Rectángulo se le llama clase derivada. Un rectángulo es un tipo de cuadrilátero, pero es incorrecto decir que un cuadrilátero es un rectángulo.
Por lo general, la herencia produce clases derivadas con más características que sus clases base, de modo que los términos superclases y subclases pueden ser confusos; evitaremos estos términos . Los objetos de clases  derivadas pueden considerarse  como objetos de sus propias clases base; esto implica que existen más objetos asociados con las clases base y menos objetos asociados con las clases derivadas, así que es razonable llamar las clases base “superclases” y a las clases derivadas “subclases”.

La herencia forma estructuras jerárquicas en forma de árboles. Una clase base existe en una relación jerarquíca con sus clase derivadas. Una clase ciertamente puede existir por sí misma, pero cuando se utiliza la clase con el mecanismo de herencia que la clase se convierte en una clase base que suministra los atributos y el comportamiento para otras clases, o en una clase derivada que hereda los atributos y comportamientos.




Con la clase herencia pública, los miembros públicos y protegidos de la clase base se heredan como miembros públicos y privados,  respectivamente. Recuerde que los miembros privados de una clase baso no están accesibles desde las clases derivadas de dicha clase. Observe que las funciones amigas no se heredan.
Es posible tratar a los objetos de clases base y a los objetos de clase derivadas de manera similar; es similitud se expresa en los atributos y en el comportamiento de la clase. Los objetos de cualquier clase derivada mediante herencia pública de una clase base común pueden tratarse  como objetos de la clase base. 




Sobrecarga de los operadores de inserción y de extracción de flujo.

C++ es capaz de introducir y desplegar los tipos de datos integrados a través de los operadores de inserción << y de extracción>> de flujo. Estos operadores están sobrecargados (en la biblioteca de clases provista con los compiladores de C++) para procesar cada tipo de dato integrado, incluso cadenas, apuntadores y char* de estilo C. Los operadores de inserción y de extracción de flujo también pueden sobrecargarse para introducir y desplegar tipos de dato definidos por el usuario.


Ejemplo de sobrecarga de inserción y extracción de flujo.






Fundamentos de la sobrecarga de operadores
La programación en C++ es sensible a los tipos y a los procesos que se enfocan en ellos. Los programadores pueden utilizar tipos integrados y pueden definir nuevos tipos. Los tipos integrados pueden utilizarse con la rica colección de operadores de C++. Los operadores proporcionan a los programadores una notación concisa para expresar manipulaciones a objetos de tipos integrados.
Los programadores también pueden utilizar operadores con tipos definidos por el usuario. Aunque C++ no permite la creación de nuevos operadores, sí permite que la mayoría de los operadores existentes se  sobrecarguen para que cuando se utilicen con objetos clase, los operadores tengan un significado apropiado para los nuevos tipos.
La sobrecarga de operadores contribuye a la extensibilidad de C++, uno de los atributos más atractivos del lenguaje.
Utilice la sobre de operadores,  cuando ésta haga que los programas sean más claros que si utilizara llamadas explícitas a funciones para realizar las mismas operaciones.
Aunque la sobrecarga de operadores puede sonar como una capacidad exótica, la mayoría de los programadores con frecuencia utilizan implícitamente operadores sobrecargados. Los operadores se sobrecargan escribiendo una definición de  función (con un encabezado y un cuerpo) como normalmente lo haría, con la excepción de que el nombre de la función ahora se convierte en la palabra reservada operator, seguida por el símbolo del operador que se está sobrecargado. Por ejemplo, el nombre de la función operator+  se utilizaría para sobrecargar el operador suma (+).
Para utilizar un operador sobre clases de objetos, ese operador debe sobrecargarse (existen dos excepciones) El operador de asignación (=) puede utilizarse con todas las clases, sin una sobrecarga explícita. El comportamiento predeterminad del operador de asignación predeterminada de miembros es peligrosa para las clases. Pronto veremos que dicha asignación predeterminada de miembros es peligrosa para las clases con miembros apuntadores; explícitamente sobrecargaremos el operador de asignación para dichas clases. El operador de dirección (&) también puede utilizarse con objetos de cualquier clase sin tener que sobrecargarlos; éste simplemente devuelve la dirección del objeto en memoria. El operador de dirección también puede sobrecargarse.
La sobrecarga es más adecuada para clases matemáticas. Éstas con frecuencia requieren de un conjunto completo de operadores sobrecargados, para garantizar la consistencia con la forma en que se manejan realmente esas clases matemáticas.
El propósito de la sobrecarga de operadores es proporcionar las mismas expresiones concisas para tipos definidos por el usuario, que C++ proporciona en su rica colección de operadores para tipos integraos, Sin embargo, la soobrecarga de operadores no es automática; el programador debe escribir funciones para la sobrecarga de operedadores, de tal modo que realicen operaciones deseadas. Algunas veces, estas funciones se realizan mejor  con funciones miembro; en ocasiones, son mejores como funciones friend y en otras, pueden hacerse con funciones no miembro y no friend.

Es posible abusar en extremo de la sobrecarga, como el caso del operador +, para realizar operaciones de tipo sustracción, o como en el caso del operador /, para realizar operaciones de tipo multiplicación. Tales usos de la sobrecarga hacen que un programa se extremadamente difícil de entender.
Al menos un argumento de una función operador debe ser un objeto de clase o una referencia a un objeto de clase. Esto evita que los programadores modifiquen la forma en que los operadores funcionan con tipos integrados.
Sobrecargar un operador de asignación y un operador de suma para permitir instrucciones como:                              objeto2 = objeto2 + objeto 1; no implica que el operador += también se sobrecargue para permitir funciones como: objeto 2 += objeto1; Tal comportamiento puede lograrse sobrecargando explícitamente el operador += para esa clase.

Ejemplo de sobrecarga de operadores