SlideShare una empresa de Scribd logo
1 de 26
Descargar para leer sin conexión
Índice


1.     ¿QUÉ ES LA PROGRAMACIÓN ORIENTADA A OBJETOS? .......................................... 1
     1.1.        MOTIVACIÓN ........................................................................................................................ 1
     1.2.        CÓMO SE PIENSA EN OBJETOS ............................................................................................... 1
2.     CLASES EN POO ....................................................................................................................... 2
     2.1.        PROPIEDADES EN CLASES ...................................................................................................... 4
     2.2.        MÉTODOS EN LAS CLASES ..................................................................................................... 4
3.     OBJETOS EN POO .................................................................................................................... 4
     3.1.        ESTADOS EN OBJETOS ........................................................................................................... 5
     3.2.        MENSAJES EN OBJETOS ......................................................................................................... 5
4.     EL PUNTERO THIS................................................................................................................... 6
5.     FUNCIONES MIEMBRO ESTÁTICAS................................................................................... 7
6.     CONSTRUCTORES ................................................................................................................... 7
7.     DESTRUCTORES ...................................................................................................................... 8
8.     CREACIÓN Y SUPRESIÓN DINÁMICA DE OBJETOS...................................................... 8
9.     SOBRECARGA DE FUNCIONES Y OPERADORES............................................................ 9
     9.1.        SOBRECARGA DE FUNCIONES ................................................................................................ 9
     9.2.        SOBRECARGA DE OPERADORES ........................................................................................... 10
     9.3.        DECLARACIÓN DE FUNCIONES OPERADOR .......................................................................... 11
     9.4.        SOBRECARGA DE OPERADORES UNITARIOS ......................................................................... 11
     9.5.        VERSIONES PREFIJA Y POSTFIJA DE LOS OPERADORES ++ Y -- ............................................. 11
     9.6.        SOBRECARGA DE OPERADORES BINARIOS ........................................................................... 12
     9.7.        SOBRECARGANDO EL OPERADOR DE LLAMADA A FUNCIONES ( )......................................... 14
     9.8.        SOBRECARGANDO EL OPERADOR SUBÍNDICE [ ] .................................................................. 14
     9.9.        SOBRECARGA DE OPERADORES DE FLUJO............................................................................ 14
10.          HERENCIA........................................................................................................................... 15
     10.1.       INTRODUCCIÓN ................................................................................................................... 15
     10.2.       CLASES DERIVADAS ............................................................................................................ 16
     10.3.       CONCEPTOS FUNDAMENTALES DE DERIVACIÓN .................................................................. 16
     10.4.       LA HERENCIA EN C++......................................................................................................... 17
     10.5.       CREACIÓN DE UNA CLASE DERIVADA .................................................................................. 17
     10.6.       CLASES DE DERIVACIÓN ..................................................................................................... 17
     10.7.       CONSTRUCTORES Y DESTRUCTORES EN HERENCIA.............................................................. 18
     10.8.       REDEFINICIÓN DE FUNCIONES MIEMBRO HEREDADAS ......................................................... 18
     10.9.       HERENCIA MÚLTIPLE .......................................................................................................... 18
     10.10.         CONSTRUCTORES Y DESTRUCTORES EN HERENCIA MÚLTIPLE ........................................ 19
     10.11.         HERENCIA REPETIDA ...................................................................................................... 19
     10.12.         CLASES BASE VIRTUALES ............................................................................................... 19
11.          POLIMORFISMO................................................................................................................ 20
12.          EJEMPLO ............................................................................................................................. 20
13.          OPERADORES..................................................................................................................... 21
     13.1.       OPERADORES ESPECIALES DE C++...................................................................................... 21
     13.2.       OPERADOR DE RESOLUCIÓN DE ÁMBITO ............................................................................. 21
     13.3.       ASIGNACIÓN DINÁMICA DE MEMORIA: NEW Y DELETE ........................................................ 21
14.          ENTRADAS Y SALIDAS BÁSICAS .................................................................................. 22
     14.1.       LA BIBLIOTECA IOSTREAM .................................................................................................. 22
     14.2.       MANIPULADORES DE SALIDA .............................................................................................. 23



                                                                          i
15.   COMPILACIÓN SEPARADA ............................................................................................ 24




                                                          ii
Programación Orientada a Objetos




1. ¿Qué es la Programación Orientada a Objetos?
   La Programación Orientada a Objetos (POO) es una forma especial de programar, más
cercana a como expresaríamos las cosas en la vida real que otros tipos de programación.
   Con la POO tenemos que aprender a pensar las cosas de una manera distinta, para escribir
nuestros programas en términos de objetos, propiedades, métodos y otras cosas que veremos
rápidamente para aclarar conceptos y dar una pequeña base que permita soltarnos un poco
con este tipo de programación

1.1. Motivación
   Durante años, los programadores se han dedicado a construir aplicaciones muy parecidas
que resolvían una y otra vez los mismos problemas. Para conseguir que los esfuerzos de los
programadores puedan ser utilizados por otras personas se creó la POO. Que es una serie de
normas de realizar las cosas de manera que otras personas puedan utilizarlas y adelantar su
trabajo, de manera que consigamos que el código se pueda reutilizar.
   La POO no es difícil, pero es una manera especial de pensar, a veces subjetiva de quien la
programa, de manera que la forma de hacer las cosas puede ser diferente según el
programador. Aunque podamos hacer los programas de formas distintas, no todas ellas son
correctas, lo difícil no es programar orientado a objetos sino programar bien. Programar bien
es importante porque así nos podemos aprovechar de todas las ventajas de la POO.

1.2. Cómo se piensa en objetos
   Pensar en términos de objetos es muy parecido a cómo lo haríamos en la vida real. Por
ejemplo vamos a pensar en un coche para tratar de modelizarlo en un esquema de POO.
Diríamos que el coche es el elemento principal que tiene una serie de características, como
podrían ser el color, el modelo o la marca. Además tiene una serie de funcionalidades
asociadas, como pueden ser ponerse en marcha, parar o aparcar.
   Pues en un esquema POO el coche sería el objeto, las propiedades serían las características
como el color o el modelo y los métodos serían las funcionalidades asociadas como ponerse
en marcha o parar.
   Por poner otro ejemplo vamos a ver cómo modelizaríamos en un esquema POO una
fracción, es decir, esa estructura matemática que tiene un numerador y un denominador que
divide al numerador, por ejemplo 3/2.
   La fracción será el objeto y tendrá dos propiedades, el numerador y el denominador.
Luego podría tener varios métodos como simplificarse, sumarse con otra fracción o número,
restarse con otra fracción, etc.
    Estos objetos se podrán utilizar en los programas, por ejemplo en un programa de
matemáticas harás uso de objetos fracción y en un programa que gestione un taller de coches
utilizarás objetos coche. Los programas Orientados a Objetos utilizan muchos objetos para
realizar las acciones que se desean realizar y ellos mismos también son objetos. Es decir, el
taller de coches será un objeto que utilizará objetos coche, herramienta, mecánico, recambios,
etc.




                                                                                             1
Programación Orientada a Objetos



2. Clases en POO
   Las clases son declaraciones de objetos, también se podrían definir como abstracciones de
objetos. Esto quiere decir que la definición de un objeto es la clase. Cuando programamos un
objeto y definimos sus características y funcionalidades en realidad lo que estamos haciendo
es programar una clase. En los ejemplos anteriores en realidad hablábamos de las clases
coche o fracción porque sólo estuvimos definiendo, aunque por encima, sus formas.
   Definición: Una clase es la implementación de un tipo de datos abstracto (TDA). Define
atributos y métodos que implementan la estructura de datos y operaciones del TDA,
respectivamente. Las instancias de las clases son llamadas objetos. Consecuentemente, las
clases definen las propiedades y el comportamiento de conjuntos de objetos.
  La sintaxis de una clase es:

                           class nombre_clase
                           {
                             miembro1;
                             miembro2;
                             ...
                             funcion_miembro1();
                             funcion_miembro2();
                             ...
                           };



   Una clase es sintácticamente igual a una estructura, con la única diferencia de que en el
tipo class todos los miembros son por defecto privados mientras que en el tipo struct son por
defecto públicos.
   En C se utiliza el término variable estructura para referirse a una variable de tipo
estructura. En C++ no se utiliza el término variable de clase, sino instancia de la clase.
El término objeto es muy importante y no es más que una variable, que a su vez no es más
que una instancia de una clase. Por consiguiente una clase es:

                           class cliente
                           {
                             char nom[20];
                             char num;
                           };

   y un objeto de esta clase se declara:      cliente cli;
   Una definición de una clase consta de dos partes: una declaración y una implementación.
La declaración lista los miembros de la clase. La implementación o cuerpo define las
funciones de la clase.
   Una de las características fundamentales de una clase es ocultar tanta información como
sea posible. Por consiguiente, es necesario imponer ciertas restricciones en el modo en que se
puede manipular una clase y de cómo se pueden utilizar los datos y el código dentro de una
clase.



                                                                                             2
Programación Orientada a Objetos


   Una clase puede contener partes públicas y partes privadas. Por defecto, todos los
miembros definidos en la clase son privados. Para hacer las partes de una clase públicas (esto
es, accesibles desde cualquier parte del programa) deben declararse después de la palabra
reservada public. Todas las variables o funciones definidas después de public son accesibles a
las restantes funciones del programa. Dado que una característica clave de la POO es la
ocultación de datos, debe tenerse presente que aunque se pueden tener variables públicas,
desde un punto de vista conceptual se debe tratar de limitar o eliminar su uso. En su lugar,
deben hacerse todos los datos privados y controlar el acceso a ellos a través de funciones
públicas.

                           class articulo
                           {
                             private:
                                      float precio;
                                      char nombre[];
                             public:
                                      void indicar();
                           };



   Por defecto u omisión todo lo declarado dentro de una clase es privado y sólo se puede
acceder a ello con las funciones miembro declaradas en el interior de la clase o con funciones
amigas.
   Los miembros que se declaran en la sección protegida de una clase sólo pueden ser
accedidos por funciones miembro declaradas dentro de la clase, por funciones amigas o por
funciones miembro de clases derivadas.
   A los miembros que se declaran en la región pública de una clase se puede acceder a
través de cualquier objeto de la clase de igual modo que se accede a los miembros de una
estructura en C.

         class alfa
         {
           int x;       //miembros dato privados
           float y;
           char z;
         public:
           double k;            //miembro dato público
           void fijar(int,float,char); //funciones miembro públicas
           void visualizar();
         };
         void main()
         {
           alba obj; //declaración de un objeto
           obj.fijar(3,2.1,'a'); //invocar a una función miembro
           obj.visualizar();          //invocar a una función miembro
           obj.x=4; //error: no se puede acceder a datos privados
           obj.k=3.2; //válido: k está en la región pública



                                                                                             3
Programación Orientada a Objetos


          }

   La definición de funciones miembro es muy similar a la definición ordinaria de función.
Tienen una cabecera y un cuerpo y pueden tener tipos y argumentos. Sin embargo, tienen dos
características especiales:
   a)     Cuando se define una función miembro se utiliza el operador de resolución de
          ámbito (::) para identificar la clase a la que pertenece la función.
   b)     Las funciones miembro (métodos) de las clases pueden acceder a las componentes
          privadas de la clase.

Opción 1                                         Opción 2
Class ejemplo                                    class ejemplo
{                                                {
  int x,y;                                        int x,y;
public:                                          Public:
  Void f()                                         Void f();
  {                                              };
           cout<<quot;x= quot;<<x<<quot; y= quot;<<y<<endl;      void ejemplo::f()
  }                                              {
};                                               cout<<quot;x= quot;<<x<<quot; y= quot;<<y<<endl;
                                                 }

  En la primera opción la función está en línea (inline). Por cada llamada a esta función, el
compilador genera (vuelve a copiar) las diferentes instrucciones de la función. En la segunda
opción (la más deseable) la función f se llamará con una llamada verdadera de función.
   La declaración anterior significa que la función f es miembro de la clase ejemplo. El
nombre de la clase a la cual está asociada la función miembro se añade como prefijo al
nombre de la función. El operador :: separa el nombre de la clase del nombre de la función.
Diferentes clases pueden tener funciones del mismo nombre y la sintaxis indica la clase
asociada con la definición de la función.


2.1. Propiedades en clases
   Las propiedades o atributos son las características de los objetos. Cuando definimos una
propiedad normalmente especificamos su nombre y su tipo. Nos podemos hacer a la idea de
que las propiedades son algo así como variables donde almacenamos datos relacionados con
los objetos.

2.2. Métodos en las clases
   Son las funcionalidades asociadas a los objetos. Cuando estamos programando las clases
las llamamos métodos. Los métodos son como funciones que están asociadas a un objeto.

3. Objetos en POO
   Los objetos son ejemplares de una clase cualquiera. Cuando creamos un ejemplar tenemos
que especificar la clase a partir de la cual se creará. Esta acción de crear un objeto a partir de
una clase se llama instanciar (que viene de una mala traducción de la palabra instance que en
inglés significa ejemplar). Por ejemplo, un objeto de la clase fracción es por ejemplo 3/5. El


                                                                                                4
Programación Orientada a Objetos


concepto o definición de fracción sería la clase, pero cuando ya estamos hablando de una
fracción en concreto 4/7, 8/1000 o cualquier otra, la llamamos objeto.
  Para crear un objeto se tiene que escribir una instrucción especial que puede ser distinta
dependiendo del lenguaje de programación que se emplee, pero será algo parecido a esto.
  miCoche = new Coche() ;
   Con la palabra new especificamos que se tiene que crear una instancia de la clase que
sigue a continuación. Dentro de los paréntesis podríamos colocar parámetros con los que
inicializar el objeto de la clase coche.
   Definición: Un objeto es una instancia de una clase. Puede ser identificado en forma
única por su nombre y define un estatus, el cuál es representado por los valores de sus
atributos en un momento en particular.

3.1. Estados en objetos
  Cuando tenemos un objeto sus propiedades toman valores. Por ejemplo, cuando tenemos
un coche la propiedad color tomará un valor en concreto, como por ejemplo rojo o gris
metalizado. El valor concreto de una propiedad de un objeto se llama estado.
  Para acceder a un estado de un objeto para ver su valor o cambiarlo se utiliza el operador
punto.
  miCoche.color = rojo ;
   El objeto es miCoche, luego colocamos el operador punto y por último el nombre e la
propiedad a la que deseamos acceder. En este ejemplo estamos cambiando el valor del estado
de la propiedad del objeto a rojo con una simple asignación.
   El estatus de un objeto cambia de acuerdo a los métodos que le son aplicados. Nos
referimos a esta posible secuencia de cambios de estatus como el comportamiento del objeto :
  Definición (Comportamiento) El comportamiento de un objeto es definido por un
conjunto de métodos que le pueden ser aplicados.
   Tenemos presentados ahora dos conceptos principales de orientación a objetos, clase y
objeto. La programación orientada a objetos es por lo tanto la implementación de tipos de
datos abstractos o, en palabras más sencillas, la escritura de clases. En quot;runtimequot;, instancias
de estas clases -los objetos- cumplen con el objetivo del programa cambiando sus estatus. Por
consecuencia, tu puedes pensar que la ejecución de tu programa constituye una colección de
objetos. Se genera la pregunta : ¿ Cómo interactúan estos objetos? De modo que
introducimos el concepto de mensaje en la sección siguiente.

3.2. Mensajes en objetos
   Un mensaje en un objeto es la acción de efectuar una llamada a un método. Por ejemplo,
cuando le decimos a un objeto coche que se ponga en marcha estamos pasándole el mensaje
“ponte en marcha”.
   Para mandar mensajes a los objetos utilizamos el operador punto, seguido del método que
deseamos invocar.
  miCoche.ponerseEnMarcha() ;
  En este ejemplo pasamos el mensaje ponerseEnMarcha(). Hay que colocar paréntesis igual
que cualquier llamada a una función, dentro irían los parámetros.



                                                                                              5
Programación Orientada a Objetos


  Definición (Mensaje) Un mensaje es una solicitud a un objeto para invocar uno de sus
métodos. Un mensaje por lo tanto contiene
                •   el nombre del método y
                •   los argumentos del método.
   Por consecuencia, la invocación de un método es solamente una reacción causada por el
hecho de recibir un mensaje. Esto solamente es posible si el método es realmente conocido
por el objeto.
   Definición: Un método está asociado a una clase. Un objeto invoca un método como una
reacción al recibir un mensaje.

4. El puntero this
   Nunca se puede llamar a una función miembro privada de una clase a menos que se asocie
con un objeto. En C cada vez que se utiliza un puntero para acceder a los miembros de una
estructura, debe utilizarse el operador de puntero (->) para acceder a los datos. ¿Cómo sabe
una función miembro cuál es la instancia de una clase asociada con ella?
   El método utilizado por C++ es añadir un argumento extra oculto a las funciones miembro.
Este argumento es un puntero al objeto de la clase que lo enlaza con la función asociada y
recibe un nombre especial denominado this.
   Dentro de una función miembro, this apunta al objeto asociado con la invocación de la
función miembro. El tipo de this en una función miembro de una clase T es T *const es
decir, un puntero constante a un objeto de tipo T.
   Normalmente, el programador no necesita preocuparse por este puntero, ya que C++
realiza la operación automáticamente, haciendo el uso de this transparente a las funciones
miembro que la utilizan. Dentro de una función miembro, se pueden hacer referencias a los
miembros del objeto asociado a ella con el prefijo this y el operador de acceso ->. Sin
embargo, este proceso no es necesario, ya que es redundante. Consideremos como ejemplo el
constructor de una clase que manipula números complejos:

          complejo::complejo (float a,float b)
          {
                     real=a;
                     imag=b;
          }
          Este constructor se puede escribir:
          complejo::complejo (float a,float b)
          {
                     this->real=a;
                     this->imag=b;
          }
          this->nombre_miembro : apunta a un miembro
          *this : es el objeto total. Es un valor constante
          this : es la dirección del objeto apuntado




                                                                                           6
Programación Orientada a Objetos



5. Funciones miembro estáticas
   Las funciones miembro static sólo pueden acceder a otras funciones y datos declarados en
una clase, pero no pueden manipular funciones ni datos no estáticos. La razón de esta
característica es que una función miembro static no tiene asignado un puntero this y por ello
no puede acceder a miembros dato de la clase a menos que se pase explícitamente este
puntero this.

6. Constructores
   Un constructor es una función especial que sirve para construir o inicializar objetos. En
C++ la inicialización de objetos no se puede realizar en el momento en que son declarados;
sin embargo, tiene una característica muy importante y es disponer de una función llamada
constructor que permite inicializar objetos en el momento en que se crean.
Un constructor es una función que sirve para construir un nuevo objeto y asignar valores a
sus miembros dato. Se caracteriza por:
  -   Tener el mismo nombre de la clase que inicializa
  -   Puede definirse inline o fuera de la declaración de la clase
  -   No devuelve valores
  -   Puede admitir parámetros como cualquier otra función
  -   Puede existir más de un constructor, e incluso no existir
   Si no se define ningún constructor de una clase, el compilador generará un constructor por
defecto. El constructor por defecto no tiene argumentos y simplemente sitúa ceros en cada
byte de las variables instancia de un objeto. Si se definen constructores para una clase, el
constructor por defecto no se genera.
   Un constructor del objeto se llama cuando se crea el objeto implícitamente: nunca se llama
explícitamente a las funciones constructoras. Esto significa que se llama cuando se ejecuta la
declaración del objeto. También, para objetos locales, el constructor se llama cada vez que la
declaración del objeto se encuentra. En objetos globales, el constructor se llama cuando se
arranca el programa.
   El constructor por defecto es un constructor que no acepta argumentos. Se llama cuando se
define una instancia pero no se especifica un valor inicial.
   Se pueden declarar en una clase constructores múltiples, mientras tomen parte diferentes
tipos o número de argumentos. El compilador es entonces capaz de determinar
automáticamente a qué constructor llamar en cada caso, examinando los argumentos.
Los argumentos por defecto se pueden especificar en la declaración del constructor. Los
miembros dato se inicializarán a esos valores por defecto, si ningún otro se especifica.
   C++ ofrece un mecanismo alternativo para pasar valores de parámetros a miembros dato.
Este mecanismo consiste en inicializar miembros dato con parámetros.

          class prueba
          {
            tipo1 d1;
            tipo2 d2;
            tipo3 d3;
          public:


                                                                                             7
Programación Orientada a Objetos


           prueba(tipo1 p1, tipo2 p2, tipo3 p3):d1(p1),d2(p2),d3(p3)
           { }
          };

  Un constructor que crea un nuevo objeto a partir de uno existente se llama constructor
copiador o de copias. El constructor de copias tiene sólo un argumento: una referencia
constante a un objeto de la misma clase. Un constructor copiador de una clase complejo es:

          complejo::complejo(const complejo &fuente)
          {
            real=fuente.real;
            imag=fuente.imag;
          }

   Si no se incluye un constructor de copia, el compilador creará un constructor de copia por
defecto. Este sistema funciona de un modo perfectamente satisfactorio en la mayoría de los
casos, aunque en ocasiones puede producir dificultades. El constructor de copia por defecto
inicializa cada elemento de datos del objeto a la izquierda del operador = al valor del elmento
dato equivalente del objeto de la derecha del operador =. Cuando no hay punteros invicados,
eso funciona bien. Sin embargo, cuando se utilizan punteros, el constructor de copia por
defecto inicializará el valor de un elemento puntero de la izquierda del operador = al del
elemento equivalente de la derecha del operador; es decir que los dos punteros apuntan en la
misma dirección. Si ésta no es la situación que se desea, hay que escribir un constructor de
copia.

7. Destructores
   Un destructor es una función miembro con igual nombre que la clase, pero precedido por
el carácter ~. Una clase sólo tiene una función destructor que, no tiene argumentos y no
devuelve ningún tipo. Un destructor realiza la operación opuesta de un constructor, limpiando
el almacenamiento asignado a los objetos cuando se crean. C++ permite sólo un destructor
por clase. El compilador llama automáticamente a un destructor del objeto cuando el objeto
sale fuera del ámbito. Si un destructor no se define en una clase, se creará por defecto un
destructor que no hace nada.
  Normalmente los destructores se declaran public.

8. Creación y supresión dinámica de objetos
   Los operadores new y delete se pueden utilizar para crear y destruir objetos de una clase,
así como dentro de funciones constructoras y destructoras
   Un objeto de una determinada clase se crea cuando la ejecución del programa entra en el
ámbito en que está definida y se destruye cuando se llega al final del ámbito. Esto es válido
tanto para objetos globales como locales, ya que los objetos globales se crean al comenzar el
programa y se destruyen al salir de él. Sin embargo, se puede crear un objeto también
mediante el operador new, que asigna la memoria necesaria para alojar el objeto y devuelve
su dirección, en forma de puntero, al objeto en cuestión.
  Los constructores normalmente implican la aplicación de new.

          p =new int(9) //p es un puntero a int inicializado a 9



                                                                                              8
Programación Orientada a Objetos


          cadena cad1(quot;holaquot;);
          cadena *cad2=new cadena;



   Un objeto creado con new no tiene ámbito, es decir, no se destruye automáticamente al
salir fuera del ámbito, sino que existe hasta que se destruye explícitamente mediante el
operador delete.

          class cadena
          {
            char *datos;
          public:
            cadena(int);
            ~cadena();
          };
          cadena::cadena(int lon)
          {
            datos=new char[lon];
          }
          cadena::~cadena()
          {
            delete datos;
          }




9. Sobrecarga de funciones y operadores
   C++ proporciona las herramientas necesarias que permiten definir funciones y operadores
que utilizan el mismo nombre o símbolo que una función u operador incorporado. Estas
funciones y operadores se dicen que están sobrecargados y se pueden utilizar para redefinir
una función u operador definido.

9.1. Sobrecarga de funciones
   En C++ dos o más funciones pueden tener el mismo nombre representando cada una de
ellas un código diferente. Esta característica se conoce como sobrecarga de funciones.
  Una función sobrecargada es una función que tiene más de una definición.
   Estas funciones se diferencian en el número y tipo de argumentos, pero también hay
funciones sobrecargadas que devuelven tipos distintos.
  Sobrecarga se refiere al uso de un mismo nombre para múltiples significados de un
operador o una función.
   Dado el énfasis del concepto de clase, el uso principal de la sobrecarga es con las
funciones miembro de una clase. Cuando más de una función miembro con igual nombre se
declara en una clase, se dice que el nombre de la función está sobrecargado en esa clase. El
ámbito del nombre sobrecargado es el de la clase.




                                                                                           9
Programación Orientada a Objetos


   La sobrecarga de funciones amigas es similar a la de funciones miembro, con la única
diferencia de que es necesaria la palabra reservada friend al igual que en la declaración de
cualquier función amiga.

9.2. Sobrecarga de operadores
   De modo análogo a la sobrecarga de funciones, la sobrecarga de operadores permite al
programador dar nuevos significados a los símbolos de los operadores existentes en C++.
   C++ permite a los programadores sobrecargar a los operadores para tipos abstractos de
datos.
   Operadores que se pueden sobrecargar:

       +             -             *            /           %             ^             &        |
       _             '             =            <           >           <=              >=      ++
      --            <<            >>           ==            0          %%               ||     +=
      -=            *=            /=           %=           &=           |=            <<=     >>=
      []            ()            ->           ->*         new         delete


   Si un operador tiene formatos unitarios y binarios (tales como + y &) ambos formatos
pueden ser sobrecargados. Un operador unitario tiene un parámetro, mientras que un operador
binario tiene dos. El único operador ternario, ?:, no se puede sobrecargar.
   Existen una serie de operadores que no se pueden sobrecargar:


                    .                     ::                    ?:                    sizeof
   La sobrecarga de operadores en C++ tiene una serie de restricciones que es necesario tener
presente a la hora de manejar operadores sobrecargados:

     * Se pueden sobrecargar sólo los operadores definidos en C++
     * La sobrecarga de operadores funciona sólo cuando se aplica a objetos de una clase
     * No se puede cambiar la preferencia o asociatividad de los operadores en C++
     * No se puede cambiar un operador binario para funcionar con un único objeto
     * No se puede cambiar un operador unitario para funcionar con dos objetos
     * No se puede sobrecargar un operador que funcione exclusivamente con punteros



   La clave para la sobrecarga de un operador es una función incorporada a C++ que permite
al programador sustituir una función definida por el usuario para uno de los operadores
existentes.
Para sobrecargar un operador, se debe definir lo que significa la operación relativa a la clase a
la cual se aplica. Para hacer esta operación, se crea una función operador, que define su
acción. El formato general de una función operador es el siguiente:
                        tipo nombre_clase::operator op (lista_argumentos) {...}
   tipo es el tipo del valor devuelto por la operación especificada. Los operadores
sobrecargados, con frecuencia tienen un valor de retorno que es del mismo tipo que la clase
para la cual el operador se sobrecarga.


                                                                                                     10
Programación Orientada a Objetos


  Las funciones operador deben ser miembro o amigas de la clase que se está utilizando.
   Las funciones operador tienen la misma sintaxis que cualquier otra, excepto que el nombre
de la función es operator op, donde op es el operador que se sobrecarga.

9.3. Declaración de funciones operador
   Las funciones operador u operadores sobrecargados pueden ser o no miembros de una
clase. De este modo, se pueden sobrecargar funciones miembro de una clase, así como
funciones amigas.
  Una función amiga tiene un argumento para un operador unitario y dos para uno binario.
Una función miembro tiene cero argumentos para un operador unitario y uno para un
operador binario.

9.4. Sobrecarga de operadores unitarios
   Consideramos una clase t y un objeto x de tipo t y definimos un operador unitario
sobrecargado: ++, que se interpreta como: operator++(x) o bien como x.operator()
  Ejemplo:

            class vector
            {
                       double x,y;
              public:
                       void iniciar(double a, double b){x=a; y=b;}
                       void visualizar()
                       {
                                cout<<quot;vector quot;<<x<<quot;,quot;<<y<<endl;
                       }
                       double operator++(){x++;y++;}
                       };
             void main()
            {
              vector v;
              v.iniciar(2.5,7.1);
              v++;
              v.visualizar(); // visualiza 3.5 8.1
            }

9.5. Versiones prefija y postfija de los operadores ++ y --
   La versión prefija del operador de incremento se sobrecarga definiendo una versión de ++
de un parámetro; la versión postfija se sobrecarga definiendo una versión de ++ de dos
parámetros, siendo el segundo de tipo int (será un parámetro mudo).
  Sobrecargar un operador unitario como función miembro.

            class c
            { int x;
              public:



                                                                                          11
Programación Orientada a Objetos


                        c() {x=0;}
                        c(int a) {x=a;}
                        c& operator--() {--x;return *this;}
                        void visualizar() {cout<<x<<endl;}
            };
            void main()
            { c ejemplo(6);
              --ejemplo; //ejemplo.operator--();
            }

   La función --() está declarada; ya que es una función miembro, el sistema pasa el puntero
this implícitamente. Por consiguiente, el objeto que llama a la función miembro se convierte
en el operando de este operador.
  Sobrecarga de un operador unitario como una función amiga.

            class c
            { int x;
              public:
                        c() {x=0;}
                        c(int a) {x=a;}
                        friend c& operator--(c y) {--y.x;return y;}
                        void visualizar() {cout<<x<<endl;}
            };
            void main()
            { c ejemplo(6);
              --ejemplo; //operator--(ejemplo);
            }

   La función --() está definida; ya que es una función amiga, el sistema no pasa el puntero
this implícitamente. Por consiguiente, se debe pasar explícitamente el objeto.

9.6. Sobrecarga de operadores binarios
   Los operadores binarios se pueden sobrecargar pasando a la función dos argumentos. El
primer argumento es el operando izquierdo del operador sobrecargado y el segundo
argumento es el operando derecho. Suponiendo dos objetos x e y de una clase c, se define un
operador binario + sobrecargado. Entonces x + y se puede interpretar como operator+(x,y) o
como x.operator+(y
  Un operador binario puede, por consiguiente, ser definido:
  -   como un amigo de dos argumentos- como una función miembro de un argumento
      (caso más frecuente)
  -   nunca los dos a la vez
  Sobrecarga de un operador binario como función miembro
  El siguiente ejemplo muestra cómo sobrecargar un operador binario como una función
miembro:
            class binario
            {



                                                                                          12
Programación Orientada a Objetos


              int x;
            public:
              binario() {x=0;}
              binario(int a) {x=a;}
              binario operator + (binario &);
              void visualizar() {cout<<x<<endl;
            };
            binario binario::operator +(binario &a)
            {
              binario aux;
              aux.x=x+a.x;
              return aux;
            }
            void main()
            {
              binario primero(2),segundo(4),tercero;
              tercero = primero + segundo;
              tercero.visualizar();
            }
            La salida del programas es 6.



  Sobrecarga de un operador binario como una función amiga

            class binario
            {
              int x;
            public:
              binario() {x=0;}
              binario(int a) {x=a;}
              friend binario operator + (binario &,binario &);
              void visualizar() {cout<<x<<endl;
            };
            binario binario::operator +(binario &a,binario &b)
            { binario aux;
              aux.x=a.x+b.x;
              return aux; }
            void main()
            { binario primero(2),segundo(4),tercero;
                tercero = primero + segundo;
                tercero.visualizar();
            }
            La salida del programa será 6.



   La función operador binario +() está declarada; debido a que es una función amiga, el
sistema no pasa el puntero this implícitamente y, por consiguiente, se debe pasar el objeto
binario explícitamente con ambos argumentos. Como consecuencia, el primer argumento de


                                                                                         13
Programación Orientada a Objetos


la función miembro se convierte en el operando izquierdo de este operador y el segundo
argumento se pasa como operando derecho.

9.7. Sobrecargando el operador de llamada a funciones ( )
   Uno de los operadores más usuales es el operador de llamada a función y puede ser
sobrecargado. La llamada a función se considera como un operador binario
                              expresión principal (lista de expresiones)
   Donde expresión principal es un operando y lista de expresiones (que puede ser vacía) es
el otro operando.
  La función operador correspondiente es operator() y puede ser definida por el usuario para
una clase c sólo mediante una función miembro no estática.
                                 x(i)    equivale a   x.operator() (i)
                                 x(i,j) equivale a    x.operator()(x,y)

9.8. Sobrecargando el operador subíndice [ ]
   El operador [] se utiliza normalmente como índice de arrays. En realidad este operador
realiza una función útil; ocultar la aritmética de punteros. Por ejemplo, si se tiene el siguiente
array: char nombre[30]; y se ejecuta una sentencia tal como car = nombre[15]; el operador
[] dirige la sentencia de asignación para sumar 15 a la dirección base del array nombre para
localizar los datos almacenados en esta posición de memoria.
   En C++ se puede sobrecargar este operador y proporciona muchas extensiones útiles al
concepto de subíndices de arrays. [] se considera un operador binario porque tiene dos
argumentos. En el ejemplo p=x[i]
   Los argumentos son x e i. La función operador correspondiente es operator []; ésta puede
ser definida para una clase x sólo mediante un función miembro. La expresión x[i] donde x es
un objeto de una determinada clase, se interpreta como x.operator[](y).

9.9. Sobrecarga de operadores de flujo
   Las sentencias de flujos se utilizan para entradas y salidas. Los flujos no son parte de C++,
pero se implementan como clases en la biblioteca de C++. Las declaraciones para estas clases
se almacenan en el archivo de cabecera iostream.h. En C++ es posible sobrecargar los
operadores de flujo de entrada y salida de modo que pueda manipular cualquier sentencia de
flujo que incluya cualquier tipo de clase. Como se definen en el archivo de cabecera
iostream.h, estos operadores trabajan con todos los tipos predefinidos, tales como int, long,
double,char. Sobrecargando estos los operadores de flujo de entrada y salida, estos pueden
además manipular cualquier tipo de objetos de clases.
   Ejemplo de sobrecarga de los flujos << y >>
           class punto
           {
             int x,y;
           public:
             punto() {x=y=0;}
             punto (int xx,int yy) { x=xx;y=yy;}
             void fijarx(int xx) { x=xx;}
             void fijary(int yy) {y=yy;}



                                                                                                14
Programación Orientada a Objetos


             int leerx() {return x;}
             int leery() {return y;}
             friend ostream& operator << (ostream& os,const punto &p);
             friend istream& operator >> (istream& is,const punto &p);
           };
           void main()
           {
             punto p;
             cout<<p<<endl;
             p.fijarx(50);
             p.fijary(100);
             cout<<p<<endl;
             cout <<quot;introducir los valores de x e ynquot;;
             cin>>p;
             cout<<quot;se ha introducidoquot;<<p;
           }
           ostream& operator<<(ostream &os,punto &p)
           {
             os <<quot;x= quot;<<p.x<<quot;,y= quot;<<p.y;
             return os;
           }
           istream& operator>>(istream &is,punto &p)
           {
             is >>p.x>>p.y;
             return is;
           }

   Es posible poner en cascada múltiples objetos en una sentencia de flujo de salida:
             punto p1,p2,p3;
             cout<<p1<<quot;:quot;<<p2<<quot;:quot;<<p3;




10. Herencia
10.1. Introducción
   Una de las propiedades más importantes de la POO es la abstracción de datos. Esta
propiedad se manifiesta esencialmente en la encapsulación, que es la responsable de gestionar
la complejidad de grandes programas al permitir la definición de nuevos tipos de datos: las
clases.
   Sin embargo, la clase no es suficiente por sí sola para soportar diseño y programación
orientada a objetos. Se necesita un medio para relacionar unas clases con otras. Un medio son
las clases anidadas, pero sólo se resuelve parcialmente el problema, ya que las clases
anidadas no tienen las características requeridas para relacionar totalmente una clase con otra.
Se necesita un mecanismo para crear jerarquías de clases en las que la clase A sea afín a la
clase B, pero con la posibilidad de poder añadirle también características propias. Este
mecanismo es la herencia.



                                                                                              15
Programación Orientada a Objetos


   La herencia es, seguramente, la característica más potente de la POO, después de las
clases. Por herencia conocemos el proceso de crear nuevas clases, llamadas clases derivadas,
a partir de una clase base.
   En C++ la herencia se manifiesta con la creación de un tipo definido por el usuario (clase),
que puede heredar las características de otra clase ya existente o derivar las suyas a otra
nueva clase. Cuando se hereda, las clases derivadas reciben las características (estructuras de
datos y funciones) de la clase original, a las que se pueden añadir nuevas características o
modificar las características heredadas. El compilador hace realmente una copia de la clase
base en la nueva clase derivada y permite al programador añadir o modificar miembros sin
alterar el código de la clase base.
   La derivación de clases consigue la reutilización efectiva del código de la clase base para
sus necesidades. Si se tiene una clase base totalmente depurada, la herencia ayuda a reutilizar
ese código en una nueva clase. No es necesario comprender el código fuente de la clase
original, sino sólo lo que hace.

10.2. Clases derivadas
   En C++, la herencia simple se realiza tomando una clase existente y derivando nuevas
clases de ella. La clase derivada hereda las estructuras de datos y funciones de la clase
original. Además, se pueden añadir nuevos miembros a las clases derivadas y los miembros
heredados pueden ser modificados.
   Una clase utilizada para derivar nuevas clases se denomina clase base, clase padre,
superclase o ascendiente. Una clase creada de otra clase se denomina clase derivada o
subclase.
  Se pueden construir jerarquías de clases, en las que cada clase sirve como padre o raíz de
una nueva clase.

10.3. Conceptos fundamentales de derivación
   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áticos, de
cada una de sus clases base.
   Una clase derivada hereda las funciones 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.




                                                                                             16
Programación Orientada a Objetos


Los siguientes elementos de la clase no se heredan:

     - Constructores
     - Destructores
     - Funciones amigas
     - Funciones estáticas de la clase
     - Datos estáticos de la clase
     - Operador de asignación sobrecargado



   Las clases base diseñadas con el objetivo principal de ser heredadas por otras se
denominan clases abstractas. Normalmente, no se crean instancias a partir de clases
abstractas, aunque sea posible.

10.4. La herencia en C++
   En C++ existen dos tipos de herencia: simple y múltiple. La herencia simple es aquella en
la que cada clase derivada hereda de una única clase. En herencia simple, cada clase tiene un
solo ascendiente. Cada clase puede tener, sin embargo, muchos descendientes.
La herencia múltiple es aquella en la cual una clase derivada tiene más de una clase base.
Aunque el concepto de herencia múltiple es muy útil, el diseño de clases suele ser más
complejo.

10.5. Creación de una clase derivada
   Cada clase derivada se debe referir a una clase base declarada anteriormente.
La declaración de una clase derivada tiene la siguiente sintaxis:
           class clase_derivada:<especificadores_de_acceso> clase_base {...};
   Los especificadores de acceso pueden ser: public, protected o private.

10.6. Clases de derivación
   Los especificadores de acceso a las clases base definen los posibles tipos de derivación:
public, protected y private. El tipo de acceso a la clase base especifica cómo recibirá la clase
derivada a los miembros de la clase base. Si no se especifica un acceso a la clase base, C++
supone que su tipo de herencia es privado.
   - Derivación pública (public). Todos los miembros public y protected de la clase base son
accesibles en la clase derivada, mientras que los miembros private de la clase base son
siempre inaccesibles en la clase derivada.
   - Derivación privada (private). Todos los miembros de la clase base se comportan como
miembros privados de la clase derivada. Esto significa que los miembros public y protected
de la clase base no son accesibles más que por las funciones miembro de la clase derivada.
Los miembros privados de la clase siguen siendo inaccesibles desde la clase derivada.
   - Derivación protegida (protected). Todos los miembros public y protected de la clase
base se comportan como miembros protected de la clase derivada. Estos miembros no son,
pues, accesibles al programa exterior, pero las clases que se deriven a continuación podrán
acceder normalmente a estos miembros (datos o funciones).




                                                                                              17
Programación Orientada a Objetos


10.7. Constructores y destructores en herencia
   Una clase derivada puede tener tanto constructores como destructores, aunque tiene el
problema adicional de que la clase base puede tomar ambas funciones miembro especiales.
Un constructor o destructor definido en la clase base debe estar coordinado con los
encontrados en una clase derivada. Igualmente importante es el movimiento de valores de los
miembros de la clase derivada a los miembros que se encuentran en la base. En particular, se
debe considerar cómo el constructor de la clase base recibe valores de la clase derivada para
crear el objeto completo.
   Si un constructor se define tanto para la clase base como para la clase derivada, C++ llama
primero al constructor base. Después que el constructor de la base termina sus tareas, C++
ejecuta el constructor derivado.
   Cuando una clase base define un constructor, éste se debe llamar durante la creación de
cada instancia de una clase derivada, para garantizar la buena inicialización de los datos
miembro que la clase derivada hereda de la clase base. En este caso la clase derivada debe
definir a su vez un constructor que llama al constructor de la clase base proporcionándole los
argumentos requeridos.
   Un constructor de una clase derivada debe utilizar un mecanismo de pasar aquellos
argumentos requeridos por el correspondiente constructor de la clase base.
           derivada::derivada(tipo1 x, tipo2 y):base (x,y) {...}
   Otro aspecto importante que es necesario considerar es el orden en el que el compilador
C++ inicializa las clases base de una clase derivada. Cuando El compilador C++ inicializa
una instancia de una clase derivada, tiene que inicializar todas las clases base primero.
Por definición, un destructor de clases no toma parámetros. Al contrario que los
constructores, una función destructor de una clase derivada se ejecuta antes que el destructor
de la clase base.

10.8. Redefinición de funciones miembro heredadas
  Se pueden utilizar funciones miembro en una clase derivada que tengan el mismo nombre
que otra de una clase base.
   La redefinición de funciones se realiza mediante funciones miembro sobrecargadas en la
clase derivada. Una función miembro redefinida oculta todas las funciones miembro
heredadas del mismo nombre. Por tanto cuando en la clase base y en la clase derivada hay
una función con el mismo nombre en las dos, se ejecuta la función de la clase derivada.

10.9. Herencia múltiple
   Es la propiedad con la cual una clase derivada puede tener más de una clase base. Es más
adecuada para definir objetos que son compuestos, por naturaleza, tales como un registro
personal, un objeto gráfico.
   Sólo es una extensión de la sintaxis de la clase derivada. Introduce una cierta complejidad
en el lenguaje y el compilador, pero proporciona grandes beneficios.
                    class ejemplo: private base1, private base2 {...};
   La aplicación de clases base múltiples introduce un conjunto de ambigüedades a los
programas C++. Una de las más comunes se da cuando dos clases base tienen funciones con
el mismo nombre, y sin embargo, una clase derivada de ambas no tiene ninguna función con
ese nombre. ¿ Cómo acceden los objetos de la clase derivada a la función correcta de la clase


                                                                                            18
Programación Orientada a Objetos


base ? El nombre de la función no es suficiente, ya que el compilador no puede deducir cuál
de las dos funciones es la invocada.
  Si se tiene una clase C que se deriva de dos clases base A y B, ambas con una función
mostrar() y se define un objeto de la clase C: C objetoC, la manera de resolver la
ambigüedad es utilizando el operador de resolución de ámbito:

objetoC.A::mostrar(); //se refiere a la versión de //mostrar() de la clase A
objetoC.B::mostrar(); //se refiere a la versión de //mostrar() de la clase B

10.10.            Constructores y destructores en herencia múltiple
  El uso de funciones constructor y destructor en clases derivadas es más complejo que en
una clase simple. Al crear clases derivadas con una sola clase base, se observa que el
constructor de la clase base se llama siempre antes que el constructor de la clase derivada.
Además se dispone de un mecanismo para pasar los valores de los parámetros necesarios al
constructor base desde el constructor de la clase derivada. Así, la sentencia siguiente pasa el
puntero a carácter x y el valor del entero y a la clase base:

           derivada (char *x, int y, double z): base(x,y)

   Este método se expande para efectuar más de una clase base.La sentencia:

           derivada (char *x,int y, double z): base1(x),base2(y)

   Llama al constructor base1 y pasa el valor de cadena de caracteres x y al constructor base2
le proporciona un valor entero y. Como con la herencia simple, los constructores de la clase
base se llaman antes de que se ejecuten al constructor de la clase derivada. Los constructores
se llaman en el orden en que se declaran las clases base.
   De modo similar, las relaciones entre el destructor de la clase derivada y el destructor de la
clase base se mantiene. El destructor derivado se llama antes de que se llame a los
destructores de cualquier base. Los destructores de las clases base se llaman en orden inverso
al orden en que los objetos base se crearon.

10.11.            Herencia repetida
   La primera regla de la herencia múltiple es que una clase derivada no puede heredar más
de una vez de una sola clase, al menos no directamente. Sin embargo, es posible que una
clase se pueda derivar dos o más veces por caminos distintos, de modo que se puede reprtir
una clase. La propiedad de recibir por herencia una misma clase más de una vez se conoce
como herencia repetida.

10.12.            Clases base virtuales
   Una clase base virtual es una clase que es compartida por otras clases base con
independencia del número de veces que esta clase se produce en la jerarquía de derivación.
Suponer , por ejemplo, que la clase T se deriva de las clases C y D cada una de las cuales se
deriva de la clase A. Esto significa que la clase T tiene dos instancias de A en su jerarquía de
derivación. C++ permite instancias múltiples de la misma clase base. Sin embargo, si sólo se
desea una instancia de la clase A para la clase T, entonces se debe declarar A como una clase
base virtual.



                                                                                               19
Programación Orientada a Objetos


  Las clases base virtuales proporcionan un método de anular el mecanismo de herencia
múltiple, permitiendo especificar una clase que es una clase base compartida.
Una clase derivada puede tener instancias virtuales y no virtuales de la misma clase base.

11. Polimorfismo
  En un sentido literal, significa la cualidad de tener más de una forma. En el contexto de
POO, el polimorfismo se refiere al hecho de que una misma operación puede tener diferente
comportamiento en diferentes objetos. Por ejemplo, consideremos la operación sumar. El
operador + realiza la suma de dos números de diferente tipo. Además se puede definir la
operación de sumar dos cadenas mediante el operador suma.




12. Ejemplo


                                                Punto
                                    -x : double = 0
                                    -y : double = 0
                                    +ponX(entrada _x : double)
                                    +ponY(entrada _y : double)
                                    +dameX() : double
                                    +dameY() : double
                                    +area() : double
                                    +perimetro() : double




                                                                         Rectangulo
               Circulo                                           -lh : double = 10
                                                                 -lv : double = 10
   -radio : double = 10
                                                                 +ponLH(entrada _lh : double)
   +ponRadio(entrada _r : double)
                                                                 +dameLV() : double
   +dameRadio() : double
                                                                 +ponLV(entrada _lv : double)
                                                                 +dameLH() : double




                                                                                                20
Programación Orientada a Objetos




13. Operadores
13.1. Operadores especiales de C++

                ::     Resolución de ámbito (o alcance)
                       Indirección (eliminación de referencia directa) un puntero a un miembro de una
                .*
                       clase
                       Indirección (eliminación de referencia directa) un puntero a un miembro de una
            ->*
                       clase
           new         Asigna (inicializa) almacenamiento dinámico
          delete       Libera almacenamiento asignado por new




13.2. Operador de resolución de ámbito
   C es un lenguaje estructurado por bloques. C++ hereda la misma noción de bloque y
ámbito. En ambos lenguajes, el mismo identificador se puede usar para referenciar a objetos
diferentes. Un uso en un bloque interno oculta el uso externo del mismo nombre. C++
introduce     el     operador      de     resolución    de     ámbito     o      de     alcance.
El operador :: se utiliza para acceder a un elemento oculto en el ámbito actual. Su sintaxis es
      :: variable

Ejemplo:
      #include <iostream.h>
     int a;
     void main()
     {
       float a;
       a=1.5;
       ::a=2;
       cout << quot;a local quot; << a << quot;nquot;;
       cout << quot;a global quot; << ::a << quot;nquot;;
     }
Este programa visualiza:

  a local 1.5
  a global 2
Este operador se utilizará también en la gestión de clases.

13.3. Asignación dinámica de memoria: new y delete
   En C la asignación dinámica de memoria se manipula con las funciones malloc() y free().
En C++ se define un método de hacer asignación dinámica utilizando los operadores new y
delete.


   En C:
       void main()
        {
          int *z;



                                                                                                        21
Programación Orientada a Objetos


              z= (int*) malloc(sizeof(int));
              *z=342;
              printf(quot;%dnquot;,*z)
              free(z);
          }

En C++:

    void main()
    {
      int *z=new int;
      *z=342;
      cout << z;
      delete z;
    }
   El operador new está disponible directamente en C++, de modo que no se necesita utilizar
ningún archivo de cabecera; new se puede utilizar con dos formatos:
          new tipo                     // asigna un único elemento
          new tipo[num_eltos]          // signa un array
   Si la cantidad de memoria solicitada no está disponible, el operador new proporciona el
valor 0.
  El operador delete libera la memoria signada con new.
              delete variable
              delete [n] variable

new es superior a malloc por tres razones:

   1. new conoce cuánta memoria se asigna a cada tipo de variable.
   2. malloc() debe indicar cuánta memoria asignar.
   3. new hace que se llame a un constructor para el objeto asignado y malloc no puede.

  delete produce una llamada al destructor en este orden:

   1. Se llama al destructor
   2. Se libera memoria

  delete es más seguro que free() ya que protege de intentar liberar memoria apuntada por un
puntero nulo.

14. Entradas y salidas básicas
14.1. La biblioteca iostream
    C++ proporciona una nueva biblioteca de funciones que realizan operaciones de E/S: la
biblioteca iostream. Esta biblioteca es una implementación orientada a objetos y está basada,
al igual que stdio, en el concepto de flujos. Cuando se introducen caracteres desde el teclado,
puede pensarse en caracteres que fluyen desde el teclado a las estructuras de datos del
programa. Cuando se escribe en un archivo, se piensa en un flujo de bytes que van del
programa al disco.
  Para acceder a la biblioteca iostream se debe incluir el archivo iostream.h. Este archivo
contiene información de diferentes funciones de E/S. Define también los objetos cin y cout.



                                                                                             22
Programación Orientada a Objetos


14.2. Manipuladores de salida
   La biblioteca iostream define varios operadores particulares, llamados manipuladores, que
le permiten controlar precisamente, el formato de los datos visualizados. Situando un
manipulador en la cadena de operadores <<, se puede modificar el estado del flujo.
   Una característica importante de un flujo que debe tratar con valores numéricos es la base
de los números. Hay tres manipuladores (dec, hex y oct) para controlar la situación. La base
por omisión es 10 y por tanto sólo será necesario indicar dec cuando se haya fijado la base a
otro valor:
cout <<oct<<x<<endl;
cout <<dec<<x<<endl;
   Los manipuladores que toman argumentos se declaran en iomanip.h, el resto en
iostream.h.

           Manipuladores          Aplicación                            Descripción
         dec               cout<<dec<<x;                    Conversión a decimal
                           cin>>dec>>x;
         hex               out<<hex<<x;                     conversión a hexadecimal
                           cin>>hex>>x;
         oct               cout<<oct<<x;                    Conversión a octal
                           cin>>oct>>x;
         ws                cin>>ws;                         Salta espacios en la entrada
         endl              cout<<endl;                      Envía carácter fin de línea
         flush             cout<<flush;                     Limpia el buffer
         setfill(int)      cout<<setfill('*';               Fija el carácter de rellenado
         setprecision(int) cout<<setprecision(6);           Fija la conversión en coma flotante al
                                                            nº de dígitos especificado
         setw(int)             cout<<setw(6)<<x;            Fija la anchura
                               cin>>setw(10)>>x;
   Con setw() los valores numéricos se justifican a derechas y los datos carácter a izquierdas.
   La información de la justificación de la salida se almacena en un modelo o patrón de bits
de una clase llamada ios, que constituye la base de todas las clases de flujos. Puede establecer
o reinicializar bits específicos utilizando los manipuladores setiosflags() y resetiosflags()
respectivamente.
   Para utilizar cualquiera de los indicadores de formato hay que insertar el manipulador
setiosflags() con el nombre del indicador como argumento. Hay que utilizar resetiosflags()
con el mismo argumento para invertir el estado del formato antes de utilizar el manipulador
setiosflags().

                 Indicador                          Significado del indicador activado
            ios::left                 Justifica la salida a la izquierda
            ios::right                Justifica la salida a la derecha
            ios::scientific           Utiliza notación científica para números de coma flotante
            ios::fixed                Utiliza notación decimal para números de coma flotante
            ios::dec                  Utiliza notación decimal para enteros
            ios::hex                  Utiliza notación hexadecimal para enteros
            ios::oct                  Utiliza notación octal para enteros
            ios::showpos              Muestra un signo positivo cuando se visualizan valores
                                      positivos




                                                                                                     23
Programación Orientada a Objetos



15. Compilación separada
   Un programa C++ consta de uno o más archivos fuente que se compilan y enlazan juntos
para formar un programa ejecutable.
   La mayoría de las bibliotecas contienen un número significativo de funciones y variables.
Para ahorrar trabajo y asegurar la consistencia cuando se hacen declaraciones externas de
estos elementos, C++ utiliza un dispositivo denominado archivo de cabecera. Un archivo de
cabecera es un archivo que contiene las declaraciones externas de una biblioteca. Estos
archivos tienen extensión .h.
   Ejemplo:
archivo max.h
   int max(int,int); //prototipo de la función – declaración de la función

archivo maximo.cpp

int max(int x, int y) //definición de la función o implementación de la función
{
  if (x>y) return(x);
  return(y);
}

archivo principal.cpp

#include <iostream.h>
#include quot;max.hquot;
void main()
{
  int a=5,b=6;
  cout<<quot;mayor quot;<<max(a,b);
}




                                                                                          24

Más contenido relacionado

La actualidad más candente

PFC: Análisis de Lenguajes Específicos de Dominio para Sistemas Embebidos
PFC: Análisis de Lenguajes Específicos de Dominio para Sistemas EmbebidosPFC: Análisis de Lenguajes Específicos de Dominio para Sistemas Embebidos
PFC: Análisis de Lenguajes Específicos de Dominio para Sistemas Embebidos
azubi
 
Algoritmos+y+flujogramas
Algoritmos+y+flujogramasAlgoritmos+y+flujogramas
Algoritmos+y+flujogramas
luis840
 
Manual Qcad
Manual QcadManual Qcad
Manual Qcad
geosam
 
Corel draw x3_-_manual_en_español
Corel draw x3_-_manual_en_españolCorel draw x3_-_manual_en_español
Corel draw x3_-_manual_en_español
RAIKO PK
 

La actualidad más candente (16)

PFC: Análisis de Lenguajes Específicos de Dominio para Sistemas Embebidos
PFC: Análisis de Lenguajes Específicos de Dominio para Sistemas EmbebidosPFC: Análisis de Lenguajes Específicos de Dominio para Sistemas Embebidos
PFC: Análisis de Lenguajes Específicos de Dominio para Sistemas Embebidos
 
Algoritmos+y+flujogramas
Algoritmos+y+flujogramasAlgoritmos+y+flujogramas
Algoritmos+y+flujogramas
 
Manual C++ 1era Parte
Manual C++ 1era ParteManual C++ 1era Parte
Manual C++ 1era Parte
 
Manual Qcad
Manual QcadManual Qcad
Manual Qcad
 
Manual de qcad
Manual de qcadManual de qcad
Manual de qcad
 
Libro.de.ORO.de.Visual.Basic.6.0.Orientado.a.Bases.de.Datos.-.2da.Ed.Bucarelly
Libro.de.ORO.de.Visual.Basic.6.0.Orientado.a.Bases.de.Datos.-.2da.Ed.BucarellyLibro.de.ORO.de.Visual.Basic.6.0.Orientado.a.Bases.de.Datos.-.2da.Ed.Bucarelly
Libro.de.ORO.de.Visual.Basic.6.0.Orientado.a.Bases.de.Datos.-.2da.Ed.Bucarelly
 
Introduccion a sql
Introduccion a sqlIntroduccion a sql
Introduccion a sql
 
Curso Dream Weaver04
Curso Dream Weaver04Curso Dream Weaver04
Curso Dream Weaver04
 
LIBRO DE ANDROID
LIBRO DE ANDROID LIBRO DE ANDROID
LIBRO DE ANDROID
 
El gran libro de android avanzado 1ed
El gran libro de android avanzado 1edEl gran libro de android avanzado 1ed
El gran libro de android avanzado 1ed
 
Corel draw x3_-_manual_en_español
Corel draw x3_-_manual_en_españolCorel draw x3_-_manual_en_español
Corel draw x3_-_manual_en_español
 
Visual Basic 6.0 progarmacion
Visual Basic 6.0 progarmacion Visual Basic 6.0 progarmacion
Visual Basic 6.0 progarmacion
 
Ec.pdf
Ec.pdfEc.pdf
Ec.pdf
 
Guia sobre corel draw x5
Guia sobre corel draw x5Guia sobre corel draw x5
Guia sobre corel draw x5
 
Manual de uso básico - Word 2007
Manual de uso básico - Word 2007Manual de uso básico - Word 2007
Manual de uso básico - Word 2007
 
Folleto desarrollado para SolidWorks 2006: Chapa metalica y piezas soldadas
Folleto desarrollado para SolidWorks 2006: Chapa metalica y piezas soldadasFolleto desarrollado para SolidWorks 2006: Chapa metalica y piezas soldadas
Folleto desarrollado para SolidWorks 2006: Chapa metalica y piezas soldadas
 

Destacado

Analisis Y DiseñO Orientado A Objetos
Analisis Y DiseñO Orientado A ObjetosAnalisis Y DiseñO Orientado A Objetos
Analisis Y DiseñO Orientado A Objetos
yoiner santiago
 
Arboles binarios
Arboles binariosArboles binarios
Arboles binarios
daniel9026
 
POO: Clases
POO: ClasesPOO: Clases
POO: Clases
Actimel
 

Destacado (20)

Ejercicios punteros cadenas-vectores
Ejercicios punteros cadenas-vectoresEjercicios punteros cadenas-vectores
Ejercicios punteros cadenas-vectores
 
Entrada y salida de datos en c
Entrada y salida de datos en cEntrada y salida de datos en c
Entrada y salida de datos en c
 
C++
C++C++
C++
 
Programación Orientada a Objetos - Resumen
Programación Orientada a Objetos - ResumenProgramación Orientada a Objetos - Resumen
Programación Orientada a Objetos - Resumen
 
Programacion Orientada a Objetos
Programacion Orientada a ObjetosProgramacion Orientada a Objetos
Programacion Orientada a Objetos
 
Conceptos de POO (Programacion Orientada a Objetos)
Conceptos de POO (Programacion Orientada a Objetos)Conceptos de POO (Programacion Orientada a Objetos)
Conceptos de POO (Programacion Orientada a Objetos)
 
Métodos POO
Métodos POOMétodos POO
Métodos POO
 
Analisis Y DiseñO Orientado A Objetos
Analisis Y DiseñO Orientado A ObjetosAnalisis Y DiseñO Orientado A Objetos
Analisis Y DiseñO Orientado A Objetos
 
Introducción a Programación Orientada a Objetos (OOP): Clases y Objetos
Introducción a  Programación Orientada a Objetos (OOP): Clases y ObjetosIntroducción a  Programación Orientada a Objetos (OOP): Clases y Objetos
Introducción a Programación Orientada a Objetos (OOP): Clases y Objetos
 
Arboles binarios
Arboles binariosArboles binarios
Arboles binarios
 
Programación pararelo
Programación parareloProgramación pararelo
Programación pararelo
 
Procesamiento en paralelo
Procesamiento en paraleloProcesamiento en paralelo
Procesamiento en paralelo
 
POO: Clases
POO: ClasesPOO: Clases
POO: Clases
 
Tema 4: Procesamiento paralelo.
Tema 4: Procesamiento paralelo.Tema 4: Procesamiento paralelo.
Tema 4: Procesamiento paralelo.
 
Vista aérea de los lenguajes de programación
Vista aérea de los lenguajes de programaciónVista aérea de los lenguajes de programación
Vista aérea de los lenguajes de programación
 
2.1 recursividad
2.1 recursividad2.1 recursividad
2.1 recursividad
 
Introduccion a la Programacion Orientada a Objetos
Introduccion a la Programacion Orientada a ObjetosIntroduccion a la Programacion Orientada a Objetos
Introduccion a la Programacion Orientada a Objetos
 
Conceptos adicionales a la programación orientada a objetos con JavaScript
Conceptos adicionales a la programación orientada a objetos con JavaScriptConceptos adicionales a la programación orientada a objetos con JavaScript
Conceptos adicionales a la programación orientada a objetos con JavaScript
 
Procesamiento paralelo
Procesamiento paraleloProcesamiento paralelo
Procesamiento paralelo
 
Recursividad
RecursividadRecursividad
Recursividad
 

Similar a Programación Orientada a Objeto

110739466 manual-basico-de-project-2010
110739466 manual-basico-de-project-2010110739466 manual-basico-de-project-2010
110739466 manual-basico-de-project-2010
89jacki38
 
Guia_plandenegocio
Guia_plandenegocioGuia_plandenegocio
Guia_plandenegocio
equiporrll
 
Programacion Concurrente
Programacion ConcurrenteProgramacion Concurrente
Programacion Concurrente
ismaelrubino
 
Programacion concurrente
Programacion concurrenteProgramacion concurrente
Programacion concurrente
gamavi
 
Planificacion estrategica e indicadores de desempeño en el sector publico
Planificacion estrategica e indicadores de desempeño en el sector publicoPlanificacion estrategica e indicadores de desempeño en el sector publico
Planificacion estrategica e indicadores de desempeño en el sector publico
oroscoush
 
Discoveramericas plan-de-negocio
Discoveramericas plan-de-negocioDiscoveramericas plan-de-negocio
Discoveramericas plan-de-negocio
Xavier Hurtado
 
2017 - Guía de iniciación WEST (Español): Modelado y Simulación en EDAR
2017 - Guía de iniciación WEST (Español): Modelado y Simulación en EDAR2017 - Guía de iniciación WEST (Español): Modelado y Simulación en EDAR
2017 - Guía de iniciación WEST (Español): Modelado y Simulación en EDAR
WALEBUBLÉ
 

Similar a Programación Orientada a Objeto (20)

110739466 manual-basico-de-project-2010
110739466 manual-basico-de-project-2010110739466 manual-basico-de-project-2010
110739466 manual-basico-de-project-2010
 
Guia_plandenegocio
Guia_plandenegocioGuia_plandenegocio
Guia_plandenegocio
 
Programacion Concurrente
Programacion ConcurrenteProgramacion Concurrente
Programacion Concurrente
 
Programacion concurrente
Programacion concurrenteProgramacion concurrente
Programacion concurrente
 
Diseño Estructurado de Algoritmos
Diseño Estructurado de AlgoritmosDiseño Estructurado de Algoritmos
Diseño Estructurado de Algoritmos
 
BD OLAP Y BI para desarrollo como profesional.pdf
BD OLAP Y BI para desarrollo como profesional.pdfBD OLAP Y BI para desarrollo como profesional.pdf
BD OLAP Y BI para desarrollo como profesional.pdf
 
3 rpm animacionporordenador_cas
3 rpm animacionporordenador_cas3 rpm animacionporordenador_cas
3 rpm animacionporordenador_cas
 
curso.pdf
curso.pdfcurso.pdf
curso.pdf
 
Proyecto Final
Proyecto FinalProyecto Final
Proyecto Final
 
Guía para la elaboración del plan de negocio cas
Guía para la elaboración del plan de negocio casGuía para la elaboración del plan de negocio cas
Guía para la elaboración del plan de negocio cas
 
Guía para la elaboración del plan de negocio cas
Guía para la elaboración del plan de negocio casGuía para la elaboración del plan de negocio cas
Guía para la elaboración del plan de negocio cas
 
6
66
6
 
PLAN DE NEGOCIO
PLAN DE NEGOCIOPLAN DE NEGOCIO
PLAN DE NEGOCIO
 
Planificacion estrategica e indicadores de desempeño en el sector publico
Planificacion estrategica e indicadores de desempeño en el sector publicoPlanificacion estrategica e indicadores de desempeño en el sector publico
Planificacion estrategica e indicadores de desempeño en el sector publico
 
Proyectos
Proyectos Proyectos
Proyectos
 
Proyectos
Proyectos Proyectos
Proyectos
 
Antologia 4to.
Antologia 4to.Antologia 4to.
Antologia 4to.
 
Discoveramericas plan-de-negocio
Discoveramericas plan-de-negocioDiscoveramericas plan-de-negocio
Discoveramericas plan-de-negocio
 
2017 - Guía de iniciación WEST (Español): Modelado y Simulación en EDAR
2017 - Guía de iniciación WEST (Español): Modelado y Simulación en EDAR2017 - Guía de iniciación WEST (Español): Modelado y Simulación en EDAR
2017 - Guía de iniciación WEST (Español): Modelado y Simulación en EDAR
 
PROYECTO FINAL
PROYECTO FINALPROYECTO FINAL
PROYECTO FINAL
 

Último

redes informaticas en una oficina administrativa
redes informaticas en una oficina administrativaredes informaticas en una oficina administrativa
redes informaticas en una oficina administrativa
nicho110
 

Último (10)

Avances tecnológicos del siglo XXI y ejemplos de estos
Avances tecnológicos del siglo XXI y ejemplos de estosAvances tecnológicos del siglo XXI y ejemplos de estos
Avances tecnológicos del siglo XXI y ejemplos de estos
 
investigación de los Avances tecnológicos del siglo XXI
investigación de los Avances tecnológicos del siglo XXIinvestigación de los Avances tecnológicos del siglo XXI
investigación de los Avances tecnológicos del siglo XXI
 
Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...
Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...
Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...
 
Buenos_Aires_Meetup_Redis_20240430_.pptx
Buenos_Aires_Meetup_Redis_20240430_.pptxBuenos_Aires_Meetup_Redis_20240430_.pptx
Buenos_Aires_Meetup_Redis_20240430_.pptx
 
redes informaticas en una oficina administrativa
redes informaticas en una oficina administrativaredes informaticas en una oficina administrativa
redes informaticas en una oficina administrativa
 
Avances tecnológicos del siglo XXI 10-07 eyvana
Avances tecnológicos del siglo XXI 10-07 eyvanaAvances tecnológicos del siglo XXI 10-07 eyvana
Avances tecnológicos del siglo XXI 10-07 eyvana
 
Innovaciones tecnologicas en el siglo 21
Innovaciones tecnologicas en el siglo 21Innovaciones tecnologicas en el siglo 21
Innovaciones tecnologicas en el siglo 21
 
EVOLUCION DE LA TECNOLOGIA Y SUS ASPECTOSpptx
EVOLUCION DE LA TECNOLOGIA Y SUS ASPECTOSpptxEVOLUCION DE LA TECNOLOGIA Y SUS ASPECTOSpptx
EVOLUCION DE LA TECNOLOGIA Y SUS ASPECTOSpptx
 
How to use Redis with MuleSoft. A quick start presentation.
How to use Redis with MuleSoft. A quick start presentation.How to use Redis with MuleSoft. A quick start presentation.
How to use Redis with MuleSoft. A quick start presentation.
 
Guia Basica para bachillerato de Circuitos Basicos
Guia Basica para bachillerato de Circuitos BasicosGuia Basica para bachillerato de Circuitos Basicos
Guia Basica para bachillerato de Circuitos Basicos
 

Programación Orientada a Objeto

  • 1. Índice 1. ¿QUÉ ES LA PROGRAMACIÓN ORIENTADA A OBJETOS? .......................................... 1 1.1. MOTIVACIÓN ........................................................................................................................ 1 1.2. CÓMO SE PIENSA EN OBJETOS ............................................................................................... 1 2. CLASES EN POO ....................................................................................................................... 2 2.1. PROPIEDADES EN CLASES ...................................................................................................... 4 2.2. MÉTODOS EN LAS CLASES ..................................................................................................... 4 3. OBJETOS EN POO .................................................................................................................... 4 3.1. ESTADOS EN OBJETOS ........................................................................................................... 5 3.2. MENSAJES EN OBJETOS ......................................................................................................... 5 4. EL PUNTERO THIS................................................................................................................... 6 5. FUNCIONES MIEMBRO ESTÁTICAS................................................................................... 7 6. CONSTRUCTORES ................................................................................................................... 7 7. DESTRUCTORES ...................................................................................................................... 8 8. CREACIÓN Y SUPRESIÓN DINÁMICA DE OBJETOS...................................................... 8 9. SOBRECARGA DE FUNCIONES Y OPERADORES............................................................ 9 9.1. SOBRECARGA DE FUNCIONES ................................................................................................ 9 9.2. SOBRECARGA DE OPERADORES ........................................................................................... 10 9.3. DECLARACIÓN DE FUNCIONES OPERADOR .......................................................................... 11 9.4. SOBRECARGA DE OPERADORES UNITARIOS ......................................................................... 11 9.5. VERSIONES PREFIJA Y POSTFIJA DE LOS OPERADORES ++ Y -- ............................................. 11 9.6. SOBRECARGA DE OPERADORES BINARIOS ........................................................................... 12 9.7. SOBRECARGANDO EL OPERADOR DE LLAMADA A FUNCIONES ( )......................................... 14 9.8. SOBRECARGANDO EL OPERADOR SUBÍNDICE [ ] .................................................................. 14 9.9. SOBRECARGA DE OPERADORES DE FLUJO............................................................................ 14 10. HERENCIA........................................................................................................................... 15 10.1. INTRODUCCIÓN ................................................................................................................... 15 10.2. CLASES DERIVADAS ............................................................................................................ 16 10.3. CONCEPTOS FUNDAMENTALES DE DERIVACIÓN .................................................................. 16 10.4. LA HERENCIA EN C++......................................................................................................... 17 10.5. CREACIÓN DE UNA CLASE DERIVADA .................................................................................. 17 10.6. CLASES DE DERIVACIÓN ..................................................................................................... 17 10.7. CONSTRUCTORES Y DESTRUCTORES EN HERENCIA.............................................................. 18 10.8. REDEFINICIÓN DE FUNCIONES MIEMBRO HEREDADAS ......................................................... 18 10.9. HERENCIA MÚLTIPLE .......................................................................................................... 18 10.10. CONSTRUCTORES Y DESTRUCTORES EN HERENCIA MÚLTIPLE ........................................ 19 10.11. HERENCIA REPETIDA ...................................................................................................... 19 10.12. CLASES BASE VIRTUALES ............................................................................................... 19 11. POLIMORFISMO................................................................................................................ 20 12. EJEMPLO ............................................................................................................................. 20 13. OPERADORES..................................................................................................................... 21 13.1. OPERADORES ESPECIALES DE C++...................................................................................... 21 13.2. OPERADOR DE RESOLUCIÓN DE ÁMBITO ............................................................................. 21 13.3. ASIGNACIÓN DINÁMICA DE MEMORIA: NEW Y DELETE ........................................................ 21 14. ENTRADAS Y SALIDAS BÁSICAS .................................................................................. 22 14.1. LA BIBLIOTECA IOSTREAM .................................................................................................. 22 14.2. MANIPULADORES DE SALIDA .............................................................................................. 23 i
  • 2. 15. COMPILACIÓN SEPARADA ............................................................................................ 24 ii
  • 3. Programación Orientada a Objetos 1. ¿Qué es la Programación Orientada a Objetos? La Programación Orientada a Objetos (POO) es una forma especial de programar, más cercana a como expresaríamos las cosas en la vida real que otros tipos de programación. Con la POO tenemos que aprender a pensar las cosas de una manera distinta, para escribir nuestros programas en términos de objetos, propiedades, métodos y otras cosas que veremos rápidamente para aclarar conceptos y dar una pequeña base que permita soltarnos un poco con este tipo de programación 1.1. Motivación Durante años, los programadores se han dedicado a construir aplicaciones muy parecidas que resolvían una y otra vez los mismos problemas. Para conseguir que los esfuerzos de los programadores puedan ser utilizados por otras personas se creó la POO. Que es una serie de normas de realizar las cosas de manera que otras personas puedan utilizarlas y adelantar su trabajo, de manera que consigamos que el código se pueda reutilizar. La POO no es difícil, pero es una manera especial de pensar, a veces subjetiva de quien la programa, de manera que la forma de hacer las cosas puede ser diferente según el programador. Aunque podamos hacer los programas de formas distintas, no todas ellas son correctas, lo difícil no es programar orientado a objetos sino programar bien. Programar bien es importante porque así nos podemos aprovechar de todas las ventajas de la POO. 1.2. Cómo se piensa en objetos Pensar en términos de objetos es muy parecido a cómo lo haríamos en la vida real. Por ejemplo vamos a pensar en un coche para tratar de modelizarlo en un esquema de POO. Diríamos que el coche es el elemento principal que tiene una serie de características, como podrían ser el color, el modelo o la marca. Además tiene una serie de funcionalidades asociadas, como pueden ser ponerse en marcha, parar o aparcar. Pues en un esquema POO el coche sería el objeto, las propiedades serían las características como el color o el modelo y los métodos serían las funcionalidades asociadas como ponerse en marcha o parar. Por poner otro ejemplo vamos a ver cómo modelizaríamos en un esquema POO una fracción, es decir, esa estructura matemática que tiene un numerador y un denominador que divide al numerador, por ejemplo 3/2. La fracción será el objeto y tendrá dos propiedades, el numerador y el denominador. Luego podría tener varios métodos como simplificarse, sumarse con otra fracción o número, restarse con otra fracción, etc. Estos objetos se podrán utilizar en los programas, por ejemplo en un programa de matemáticas harás uso de objetos fracción y en un programa que gestione un taller de coches utilizarás objetos coche. Los programas Orientados a Objetos utilizan muchos objetos para realizar las acciones que se desean realizar y ellos mismos también son objetos. Es decir, el taller de coches será un objeto que utilizará objetos coche, herramienta, mecánico, recambios, etc. 1
  • 4. Programación Orientada a Objetos 2. Clases en POO Las clases son declaraciones de objetos, también se podrían definir como abstracciones de objetos. Esto quiere decir que la definición de un objeto es la clase. Cuando programamos un objeto y definimos sus características y funcionalidades en realidad lo que estamos haciendo es programar una clase. En los ejemplos anteriores en realidad hablábamos de las clases coche o fracción porque sólo estuvimos definiendo, aunque por encima, sus formas. Definición: Una clase es la implementación de un tipo de datos abstracto (TDA). Define atributos y métodos que implementan la estructura de datos y operaciones del TDA, respectivamente. Las instancias de las clases son llamadas objetos. Consecuentemente, las clases definen las propiedades y el comportamiento de conjuntos de objetos. La sintaxis de una clase es: class nombre_clase { miembro1; miembro2; ... funcion_miembro1(); funcion_miembro2(); ... }; Una clase es sintácticamente igual a una estructura, con la única diferencia de que en el tipo class todos los miembros son por defecto privados mientras que en el tipo struct son por defecto públicos. En C se utiliza el término variable estructura para referirse a una variable de tipo estructura. En C++ no se utiliza el término variable de clase, sino instancia de la clase. El término objeto es muy importante y no es más que una variable, que a su vez no es más que una instancia de una clase. Por consiguiente una clase es: class cliente { char nom[20]; char num; }; y un objeto de esta clase se declara: cliente cli; Una definición de una clase consta de dos partes: una declaración y una implementación. La declaración lista los miembros de la clase. La implementación o cuerpo define las funciones de la clase. Una de las características fundamentales de una clase es ocultar tanta información como sea posible. Por consiguiente, es necesario imponer ciertas restricciones en el modo en que se puede manipular una clase y de cómo se pueden utilizar los datos y el código dentro de una clase. 2
  • 5. Programación Orientada a Objetos Una clase puede contener partes públicas y partes privadas. Por defecto, todos los miembros definidos en la clase son privados. Para hacer las partes de una clase públicas (esto es, accesibles desde cualquier parte del programa) deben declararse después de la palabra reservada public. Todas las variables o funciones definidas después de public son accesibles a las restantes funciones del programa. Dado que una característica clave de la POO es la ocultación de datos, debe tenerse presente que aunque se pueden tener variables públicas, desde un punto de vista conceptual se debe tratar de limitar o eliminar su uso. En su lugar, deben hacerse todos los datos privados y controlar el acceso a ellos a través de funciones públicas. class articulo { private: float precio; char nombre[]; public: void indicar(); }; Por defecto u omisión todo lo declarado dentro de una clase es privado y sólo se puede acceder a ello con las funciones miembro declaradas en el interior de la clase o con funciones amigas. Los miembros que se declaran en la sección protegida de una clase sólo pueden ser accedidos por funciones miembro declaradas dentro de la clase, por funciones amigas o por funciones miembro de clases derivadas. A los miembros que se declaran en la región pública de una clase se puede acceder a través de cualquier objeto de la clase de igual modo que se accede a los miembros de una estructura en C. class alfa { int x; //miembros dato privados float y; char z; public: double k; //miembro dato público void fijar(int,float,char); //funciones miembro públicas void visualizar(); }; void main() { alba obj; //declaración de un objeto obj.fijar(3,2.1,'a'); //invocar a una función miembro obj.visualizar(); //invocar a una función miembro obj.x=4; //error: no se puede acceder a datos privados obj.k=3.2; //válido: k está en la región pública 3
  • 6. Programación Orientada a Objetos } La definición de funciones miembro es muy similar a la definición ordinaria de función. Tienen una cabecera y un cuerpo y pueden tener tipos y argumentos. Sin embargo, tienen dos características especiales: a) Cuando se define una función miembro se utiliza el operador de resolución de ámbito (::) para identificar la clase a la que pertenece la función. b) Las funciones miembro (métodos) de las clases pueden acceder a las componentes privadas de la clase. Opción 1 Opción 2 Class ejemplo class ejemplo { { int x,y; int x,y; public: Public: Void f() Void f(); { }; cout<<quot;x= quot;<<x<<quot; y= quot;<<y<<endl; void ejemplo::f() } { }; cout<<quot;x= quot;<<x<<quot; y= quot;<<y<<endl; } En la primera opción la función está en línea (inline). Por cada llamada a esta función, el compilador genera (vuelve a copiar) las diferentes instrucciones de la función. En la segunda opción (la más deseable) la función f se llamará con una llamada verdadera de función. La declaración anterior significa que la función f es miembro de la clase ejemplo. El nombre de la clase a la cual está asociada la función miembro se añade como prefijo al nombre de la función. El operador :: separa el nombre de la clase del nombre de la función. Diferentes clases pueden tener funciones del mismo nombre y la sintaxis indica la clase asociada con la definición de la función. 2.1. Propiedades en clases Las propiedades o atributos son las características de los objetos. Cuando definimos una propiedad normalmente especificamos su nombre y su tipo. Nos podemos hacer a la idea de que las propiedades son algo así como variables donde almacenamos datos relacionados con los objetos. 2.2. Métodos en las clases Son las funcionalidades asociadas a los objetos. Cuando estamos programando las clases las llamamos métodos. Los métodos son como funciones que están asociadas a un objeto. 3. Objetos en POO Los objetos son ejemplares de una clase cualquiera. Cuando creamos un ejemplar tenemos que especificar la clase a partir de la cual se creará. Esta acción de crear un objeto a partir de una clase se llama instanciar (que viene de una mala traducción de la palabra instance que en inglés significa ejemplar). Por ejemplo, un objeto de la clase fracción es por ejemplo 3/5. El 4
  • 7. Programación Orientada a Objetos concepto o definición de fracción sería la clase, pero cuando ya estamos hablando de una fracción en concreto 4/7, 8/1000 o cualquier otra, la llamamos objeto. Para crear un objeto se tiene que escribir una instrucción especial que puede ser distinta dependiendo del lenguaje de programación que se emplee, pero será algo parecido a esto. miCoche = new Coche() ; Con la palabra new especificamos que se tiene que crear una instancia de la clase que sigue a continuación. Dentro de los paréntesis podríamos colocar parámetros con los que inicializar el objeto de la clase coche. Definición: Un objeto es una instancia de una clase. Puede ser identificado en forma única por su nombre y define un estatus, el cuál es representado por los valores de sus atributos en un momento en particular. 3.1. Estados en objetos Cuando tenemos un objeto sus propiedades toman valores. Por ejemplo, cuando tenemos un coche la propiedad color tomará un valor en concreto, como por ejemplo rojo o gris metalizado. El valor concreto de una propiedad de un objeto se llama estado. Para acceder a un estado de un objeto para ver su valor o cambiarlo se utiliza el operador punto. miCoche.color = rojo ; El objeto es miCoche, luego colocamos el operador punto y por último el nombre e la propiedad a la que deseamos acceder. En este ejemplo estamos cambiando el valor del estado de la propiedad del objeto a rojo con una simple asignación. El estatus de un objeto cambia de acuerdo a los métodos que le son aplicados. Nos referimos a esta posible secuencia de cambios de estatus como el comportamiento del objeto : Definición (Comportamiento) El comportamiento de un objeto es definido por un conjunto de métodos que le pueden ser aplicados. Tenemos presentados ahora dos conceptos principales de orientación a objetos, clase y objeto. La programación orientada a objetos es por lo tanto la implementación de tipos de datos abstractos o, en palabras más sencillas, la escritura de clases. En quot;runtimequot;, instancias de estas clases -los objetos- cumplen con el objetivo del programa cambiando sus estatus. Por consecuencia, tu puedes pensar que la ejecución de tu programa constituye una colección de objetos. Se genera la pregunta : ¿ Cómo interactúan estos objetos? De modo que introducimos el concepto de mensaje en la sección siguiente. 3.2. Mensajes en objetos Un mensaje en un objeto es la acción de efectuar una llamada a un método. Por ejemplo, cuando le decimos a un objeto coche que se ponga en marcha estamos pasándole el mensaje “ponte en marcha”. Para mandar mensajes a los objetos utilizamos el operador punto, seguido del método que deseamos invocar. miCoche.ponerseEnMarcha() ; En este ejemplo pasamos el mensaje ponerseEnMarcha(). Hay que colocar paréntesis igual que cualquier llamada a una función, dentro irían los parámetros. 5
  • 8. Programación Orientada a Objetos Definición (Mensaje) Un mensaje es una solicitud a un objeto para invocar uno de sus métodos. Un mensaje por lo tanto contiene • el nombre del método y • los argumentos del método. Por consecuencia, la invocación de un método es solamente una reacción causada por el hecho de recibir un mensaje. Esto solamente es posible si el método es realmente conocido por el objeto. Definición: Un método está asociado a una clase. Un objeto invoca un método como una reacción al recibir un mensaje. 4. El puntero this Nunca se puede llamar a una función miembro privada de una clase a menos que se asocie con un objeto. En C cada vez que se utiliza un puntero para acceder a los miembros de una estructura, debe utilizarse el operador de puntero (->) para acceder a los datos. ¿Cómo sabe una función miembro cuál es la instancia de una clase asociada con ella? El método utilizado por C++ es añadir un argumento extra oculto a las funciones miembro. Este argumento es un puntero al objeto de la clase que lo enlaza con la función asociada y recibe un nombre especial denominado this. Dentro de una función miembro, this apunta al objeto asociado con la invocación de la función miembro. El tipo de this en una función miembro de una clase T es T *const es decir, un puntero constante a un objeto de tipo T. Normalmente, el programador no necesita preocuparse por este puntero, ya que C++ realiza la operación automáticamente, haciendo el uso de this transparente a las funciones miembro que la utilizan. Dentro de una función miembro, se pueden hacer referencias a los miembros del objeto asociado a ella con el prefijo this y el operador de acceso ->. Sin embargo, este proceso no es necesario, ya que es redundante. Consideremos como ejemplo el constructor de una clase que manipula números complejos: complejo::complejo (float a,float b) { real=a; imag=b; } Este constructor se puede escribir: complejo::complejo (float a,float b) { this->real=a; this->imag=b; } this->nombre_miembro : apunta a un miembro *this : es el objeto total. Es un valor constante this : es la dirección del objeto apuntado 6
  • 9. Programación Orientada a Objetos 5. Funciones miembro estáticas Las funciones miembro static sólo pueden acceder a otras funciones y datos declarados en una clase, pero no pueden manipular funciones ni datos no estáticos. La razón de esta característica es que una función miembro static no tiene asignado un puntero this y por ello no puede acceder a miembros dato de la clase a menos que se pase explícitamente este puntero this. 6. Constructores Un constructor es una función especial que sirve para construir o inicializar objetos. En C++ la inicialización de objetos no se puede realizar en el momento en que son declarados; sin embargo, tiene una característica muy importante y es disponer de una función llamada constructor que permite inicializar objetos en el momento en que se crean. Un constructor es una función que sirve para construir un nuevo objeto y asignar valores a sus miembros dato. Se caracteriza por: - Tener el mismo nombre de la clase que inicializa - Puede definirse inline o fuera de la declaración de la clase - No devuelve valores - Puede admitir parámetros como cualquier otra función - Puede existir más de un constructor, e incluso no existir Si no se define ningún constructor de una clase, el compilador generará un constructor por defecto. El constructor por defecto no tiene argumentos y simplemente sitúa ceros en cada byte de las variables instancia de un objeto. Si se definen constructores para una clase, el constructor por defecto no se genera. Un constructor del objeto se llama cuando se crea el objeto implícitamente: nunca se llama explícitamente a las funciones constructoras. Esto significa que se llama cuando se ejecuta la declaración del objeto. También, para objetos locales, el constructor se llama cada vez que la declaración del objeto se encuentra. En objetos globales, el constructor se llama cuando se arranca el programa. El constructor por defecto es un constructor que no acepta argumentos. Se llama cuando se define una instancia pero no se especifica un valor inicial. Se pueden declarar en una clase constructores múltiples, mientras tomen parte diferentes tipos o número de argumentos. El compilador es entonces capaz de determinar automáticamente a qué constructor llamar en cada caso, examinando los argumentos. Los argumentos por defecto se pueden especificar en la declaración del constructor. Los miembros dato se inicializarán a esos valores por defecto, si ningún otro se especifica. C++ ofrece un mecanismo alternativo para pasar valores de parámetros a miembros dato. Este mecanismo consiste en inicializar miembros dato con parámetros. class prueba { tipo1 d1; tipo2 d2; tipo3 d3; public: 7
  • 10. Programación Orientada a Objetos prueba(tipo1 p1, tipo2 p2, tipo3 p3):d1(p1),d2(p2),d3(p3) { } }; Un constructor que crea un nuevo objeto a partir de uno existente se llama constructor copiador o de copias. El constructor de copias tiene sólo un argumento: una referencia constante a un objeto de la misma clase. Un constructor copiador de una clase complejo es: complejo::complejo(const complejo &fuente) { real=fuente.real; imag=fuente.imag; } Si no se incluye un constructor de copia, el compilador creará un constructor de copia por defecto. Este sistema funciona de un modo perfectamente satisfactorio en la mayoría de los casos, aunque en ocasiones puede producir dificultades. El constructor de copia por defecto inicializa cada elemento de datos del objeto a la izquierda del operador = al valor del elmento dato equivalente del objeto de la derecha del operador =. Cuando no hay punteros invicados, eso funciona bien. Sin embargo, cuando se utilizan punteros, el constructor de copia por defecto inicializará el valor de un elemento puntero de la izquierda del operador = al del elemento equivalente de la derecha del operador; es decir que los dos punteros apuntan en la misma dirección. Si ésta no es la situación que se desea, hay que escribir un constructor de copia. 7. Destructores Un destructor es una función miembro con igual nombre que la clase, pero precedido por el carácter ~. Una clase sólo tiene una función destructor que, no tiene argumentos y no devuelve ningún tipo. Un destructor realiza la operación opuesta de un constructor, limpiando el almacenamiento asignado a los objetos cuando se crean. C++ permite sólo un destructor por clase. El compilador llama automáticamente a un destructor del objeto cuando el objeto sale fuera del ámbito. Si un destructor no se define en una clase, se creará por defecto un destructor que no hace nada. Normalmente los destructores se declaran public. 8. Creación y supresión dinámica de objetos Los operadores new y delete se pueden utilizar para crear y destruir objetos de una clase, así como dentro de funciones constructoras y destructoras Un objeto de una determinada clase se crea cuando la ejecución del programa entra en el ámbito en que está definida y se destruye cuando se llega al final del ámbito. Esto es válido tanto para objetos globales como locales, ya que los objetos globales se crean al comenzar el programa y se destruyen al salir de él. Sin embargo, se puede crear un objeto también mediante el operador new, que asigna la memoria necesaria para alojar el objeto y devuelve su dirección, en forma de puntero, al objeto en cuestión. Los constructores normalmente implican la aplicación de new. p =new int(9) //p es un puntero a int inicializado a 9 8
  • 11. Programación Orientada a Objetos cadena cad1(quot;holaquot;); cadena *cad2=new cadena; Un objeto creado con new no tiene ámbito, es decir, no se destruye automáticamente al salir fuera del ámbito, sino que existe hasta que se destruye explícitamente mediante el operador delete. class cadena { char *datos; public: cadena(int); ~cadena(); }; cadena::cadena(int lon) { datos=new char[lon]; } cadena::~cadena() { delete datos; } 9. Sobrecarga de funciones y operadores C++ proporciona las herramientas necesarias que permiten definir funciones y operadores que utilizan el mismo nombre o símbolo que una función u operador incorporado. Estas funciones y operadores se dicen que están sobrecargados y se pueden utilizar para redefinir una función u operador definido. 9.1. Sobrecarga de funciones En C++ dos o más funciones pueden tener el mismo nombre representando cada una de ellas un código diferente. Esta característica se conoce como sobrecarga de funciones. Una función sobrecargada es una función que tiene más de una definición. Estas funciones se diferencian en el número y tipo de argumentos, pero también hay funciones sobrecargadas que devuelven tipos distintos. Sobrecarga se refiere al uso de un mismo nombre para múltiples significados de un operador o una función. Dado el énfasis del concepto de clase, el uso principal de la sobrecarga es con las funciones miembro de una clase. Cuando más de una función miembro con igual nombre se declara en una clase, se dice que el nombre de la función está sobrecargado en esa clase. El ámbito del nombre sobrecargado es el de la clase. 9
  • 12. Programación Orientada a Objetos La sobrecarga de funciones amigas es similar a la de funciones miembro, con la única diferencia de que es necesaria la palabra reservada friend al igual que en la declaración de cualquier función amiga. 9.2. Sobrecarga de operadores De modo análogo a la sobrecarga de funciones, la sobrecarga de operadores permite al programador dar nuevos significados a los símbolos de los operadores existentes en C++. C++ permite a los programadores sobrecargar a los operadores para tipos abstractos de datos. Operadores que se pueden sobrecargar: + - * / % ^ & | _ ' = < > <= >= ++ -- << >> == 0 %% || += -= *= /= %= &= |= <<= >>= [] () -> ->* new delete Si un operador tiene formatos unitarios y binarios (tales como + y &) ambos formatos pueden ser sobrecargados. Un operador unitario tiene un parámetro, mientras que un operador binario tiene dos. El único operador ternario, ?:, no se puede sobrecargar. Existen una serie de operadores que no se pueden sobrecargar: . :: ?: sizeof La sobrecarga de operadores en C++ tiene una serie de restricciones que es necesario tener presente a la hora de manejar operadores sobrecargados: * Se pueden sobrecargar sólo los operadores definidos en C++ * La sobrecarga de operadores funciona sólo cuando se aplica a objetos de una clase * No se puede cambiar la preferencia o asociatividad de los operadores en C++ * No se puede cambiar un operador binario para funcionar con un único objeto * No se puede cambiar un operador unitario para funcionar con dos objetos * No se puede sobrecargar un operador que funcione exclusivamente con punteros La clave para la sobrecarga de un operador es una función incorporada a C++ que permite al programador sustituir una función definida por el usuario para uno de los operadores existentes. Para sobrecargar un operador, se debe definir lo que significa la operación relativa a la clase a la cual se aplica. Para hacer esta operación, se crea una función operador, que define su acción. El formato general de una función operador es el siguiente: tipo nombre_clase::operator op (lista_argumentos) {...} tipo es el tipo del valor devuelto por la operación especificada. Los operadores sobrecargados, con frecuencia tienen un valor de retorno que es del mismo tipo que la clase para la cual el operador se sobrecarga. 10
  • 13. Programación Orientada a Objetos Las funciones operador deben ser miembro o amigas de la clase que se está utilizando. Las funciones operador tienen la misma sintaxis que cualquier otra, excepto que el nombre de la función es operator op, donde op es el operador que se sobrecarga. 9.3. Declaración de funciones operador Las funciones operador u operadores sobrecargados pueden ser o no miembros de una clase. De este modo, se pueden sobrecargar funciones miembro de una clase, así como funciones amigas. Una función amiga tiene un argumento para un operador unitario y dos para uno binario. Una función miembro tiene cero argumentos para un operador unitario y uno para un operador binario. 9.4. Sobrecarga de operadores unitarios Consideramos una clase t y un objeto x de tipo t y definimos un operador unitario sobrecargado: ++, que se interpreta como: operator++(x) o bien como x.operator() Ejemplo: class vector { double x,y; public: void iniciar(double a, double b){x=a; y=b;} void visualizar() { cout<<quot;vector quot;<<x<<quot;,quot;<<y<<endl; } double operator++(){x++;y++;} }; void main() { vector v; v.iniciar(2.5,7.1); v++; v.visualizar(); // visualiza 3.5 8.1 } 9.5. Versiones prefija y postfija de los operadores ++ y -- La versión prefija del operador de incremento se sobrecarga definiendo una versión de ++ de un parámetro; la versión postfija se sobrecarga definiendo una versión de ++ de dos parámetros, siendo el segundo de tipo int (será un parámetro mudo). Sobrecargar un operador unitario como función miembro. class c { int x; public: 11
  • 14. Programación Orientada a Objetos c() {x=0;} c(int a) {x=a;} c& operator--() {--x;return *this;} void visualizar() {cout<<x<<endl;} }; void main() { c ejemplo(6); --ejemplo; //ejemplo.operator--(); } La función --() está declarada; ya que es una función miembro, el sistema pasa el puntero this implícitamente. Por consiguiente, el objeto que llama a la función miembro se convierte en el operando de este operador. Sobrecarga de un operador unitario como una función amiga. class c { int x; public: c() {x=0;} c(int a) {x=a;} friend c& operator--(c y) {--y.x;return y;} void visualizar() {cout<<x<<endl;} }; void main() { c ejemplo(6); --ejemplo; //operator--(ejemplo); } La función --() está definida; ya que es una función amiga, el sistema no pasa el puntero this implícitamente. Por consiguiente, se debe pasar explícitamente el objeto. 9.6. Sobrecarga de operadores binarios Los operadores binarios se pueden sobrecargar pasando a la función dos argumentos. El primer argumento es el operando izquierdo del operador sobrecargado y el segundo argumento es el operando derecho. Suponiendo dos objetos x e y de una clase c, se define un operador binario + sobrecargado. Entonces x + y se puede interpretar como operator+(x,y) o como x.operator+(y Un operador binario puede, por consiguiente, ser definido: - como un amigo de dos argumentos- como una función miembro de un argumento (caso más frecuente) - nunca los dos a la vez Sobrecarga de un operador binario como función miembro El siguiente ejemplo muestra cómo sobrecargar un operador binario como una función miembro: class binario { 12
  • 15. Programación Orientada a Objetos int x; public: binario() {x=0;} binario(int a) {x=a;} binario operator + (binario &); void visualizar() {cout<<x<<endl; }; binario binario::operator +(binario &a) { binario aux; aux.x=x+a.x; return aux; } void main() { binario primero(2),segundo(4),tercero; tercero = primero + segundo; tercero.visualizar(); } La salida del programas es 6. Sobrecarga de un operador binario como una función amiga class binario { int x; public: binario() {x=0;} binario(int a) {x=a;} friend binario operator + (binario &,binario &); void visualizar() {cout<<x<<endl; }; binario binario::operator +(binario &a,binario &b) { binario aux; aux.x=a.x+b.x; return aux; } void main() { binario primero(2),segundo(4),tercero; tercero = primero + segundo; tercero.visualizar(); } La salida del programa será 6. La función operador binario +() está declarada; debido a que es una función amiga, el sistema no pasa el puntero this implícitamente y, por consiguiente, se debe pasar el objeto binario explícitamente con ambos argumentos. Como consecuencia, el primer argumento de 13
  • 16. Programación Orientada a Objetos la función miembro se convierte en el operando izquierdo de este operador y el segundo argumento se pasa como operando derecho. 9.7. Sobrecargando el operador de llamada a funciones ( ) Uno de los operadores más usuales es el operador de llamada a función y puede ser sobrecargado. La llamada a función se considera como un operador binario expresión principal (lista de expresiones) Donde expresión principal es un operando y lista de expresiones (que puede ser vacía) es el otro operando. La función operador correspondiente es operator() y puede ser definida por el usuario para una clase c sólo mediante una función miembro no estática. x(i) equivale a x.operator() (i) x(i,j) equivale a x.operator()(x,y) 9.8. Sobrecargando el operador subíndice [ ] El operador [] se utiliza normalmente como índice de arrays. En realidad este operador realiza una función útil; ocultar la aritmética de punteros. Por ejemplo, si se tiene el siguiente array: char nombre[30]; y se ejecuta una sentencia tal como car = nombre[15]; el operador [] dirige la sentencia de asignación para sumar 15 a la dirección base del array nombre para localizar los datos almacenados en esta posición de memoria. En C++ se puede sobrecargar este operador y proporciona muchas extensiones útiles al concepto de subíndices de arrays. [] se considera un operador binario porque tiene dos argumentos. En el ejemplo p=x[i] Los argumentos son x e i. La función operador correspondiente es operator []; ésta puede ser definida para una clase x sólo mediante un función miembro. La expresión x[i] donde x es un objeto de una determinada clase, se interpreta como x.operator[](y). 9.9. Sobrecarga de operadores de flujo Las sentencias de flujos se utilizan para entradas y salidas. Los flujos no son parte de C++, pero se implementan como clases en la biblioteca de C++. Las declaraciones para estas clases se almacenan en el archivo de cabecera iostream.h. En C++ es posible sobrecargar los operadores de flujo de entrada y salida de modo que pueda manipular cualquier sentencia de flujo que incluya cualquier tipo de clase. Como se definen en el archivo de cabecera iostream.h, estos operadores trabajan con todos los tipos predefinidos, tales como int, long, double,char. Sobrecargando estos los operadores de flujo de entrada y salida, estos pueden además manipular cualquier tipo de objetos de clases. Ejemplo de sobrecarga de los flujos << y >> class punto { int x,y; public: punto() {x=y=0;} punto (int xx,int yy) { x=xx;y=yy;} void fijarx(int xx) { x=xx;} void fijary(int yy) {y=yy;} 14
  • 17. Programación Orientada a Objetos int leerx() {return x;} int leery() {return y;} friend ostream& operator << (ostream& os,const punto &p); friend istream& operator >> (istream& is,const punto &p); }; void main() { punto p; cout<<p<<endl; p.fijarx(50); p.fijary(100); cout<<p<<endl; cout <<quot;introducir los valores de x e ynquot;; cin>>p; cout<<quot;se ha introducidoquot;<<p; } ostream& operator<<(ostream &os,punto &p) { os <<quot;x= quot;<<p.x<<quot;,y= quot;<<p.y; return os; } istream& operator>>(istream &is,punto &p) { is >>p.x>>p.y; return is; } Es posible poner en cascada múltiples objetos en una sentencia de flujo de salida: punto p1,p2,p3; cout<<p1<<quot;:quot;<<p2<<quot;:quot;<<p3; 10. Herencia 10.1. Introducción Una de las propiedades más importantes de la POO es la abstracción de datos. Esta propiedad se manifiesta esencialmente en la encapsulación, que es la responsable de gestionar la complejidad de grandes programas al permitir la definición de nuevos tipos de datos: las clases. Sin embargo, la clase no es suficiente por sí sola para soportar diseño y programación orientada a objetos. Se necesita un medio para relacionar unas clases con otras. Un medio son las clases anidadas, pero sólo se resuelve parcialmente el problema, ya que las clases anidadas no tienen las características requeridas para relacionar totalmente una clase con otra. Se necesita un mecanismo para crear jerarquías de clases en las que la clase A sea afín a la clase B, pero con la posibilidad de poder añadirle también características propias. Este mecanismo es la herencia. 15
  • 18. Programación Orientada a Objetos La herencia es, seguramente, la característica más potente de la POO, después de las clases. Por herencia conocemos el proceso de crear nuevas clases, llamadas clases derivadas, a partir de una clase base. En C++ la herencia se manifiesta con la creación de un tipo definido por el usuario (clase), que puede heredar las características de otra clase ya existente o derivar las suyas a otra nueva clase. Cuando se hereda, las clases derivadas reciben las características (estructuras de datos y funciones) de la clase original, a las que se pueden añadir nuevas características o modificar las características heredadas. El compilador hace realmente una copia de la clase base en la nueva clase derivada y permite al programador añadir o modificar miembros sin alterar el código de la clase base. La derivación de clases consigue la reutilización efectiva del código de la clase base para sus necesidades. Si se tiene una clase base totalmente depurada, la herencia ayuda a reutilizar ese código en una nueva clase. No es necesario comprender el código fuente de la clase original, sino sólo lo que hace. 10.2. Clases derivadas En C++, la herencia simple se realiza tomando una clase existente y derivando nuevas clases de ella. La clase derivada hereda las estructuras de datos y funciones de la clase original. Además, se pueden añadir nuevos miembros a las clases derivadas y los miembros heredados pueden ser modificados. Una clase utilizada para derivar nuevas clases se denomina clase base, clase padre, superclase o ascendiente. Una clase creada de otra clase se denomina clase derivada o subclase. Se pueden construir jerarquías de clases, en las que cada clase sirve como padre o raíz de una nueva clase. 10.3. Conceptos fundamentales de derivación 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áticos, de cada una de sus clases base. Una clase derivada hereda las funciones 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. 16
  • 19. Programación Orientada a Objetos Los siguientes elementos de la clase no se heredan: - Constructores - Destructores - Funciones amigas - Funciones estáticas de la clase - Datos estáticos de la clase - Operador de asignación sobrecargado Las clases base diseñadas con el objetivo principal de ser heredadas por otras se denominan clases abstractas. Normalmente, no se crean instancias a partir de clases abstractas, aunque sea posible. 10.4. La herencia en C++ En C++ existen dos tipos de herencia: simple y múltiple. La herencia simple es aquella en la que cada clase derivada hereda de una única clase. En herencia simple, cada clase tiene un solo ascendiente. Cada clase puede tener, sin embargo, muchos descendientes. La herencia múltiple es aquella en la cual una clase derivada tiene más de una clase base. Aunque el concepto de herencia múltiple es muy útil, el diseño de clases suele ser más complejo. 10.5. Creación de una clase derivada Cada clase derivada se debe referir a una clase base declarada anteriormente. La declaración de una clase derivada tiene la siguiente sintaxis: class clase_derivada:<especificadores_de_acceso> clase_base {...}; Los especificadores de acceso pueden ser: public, protected o private. 10.6. Clases de derivación Los especificadores de acceso a las clases base definen los posibles tipos de derivación: public, protected y private. El tipo de acceso a la clase base especifica cómo recibirá la clase derivada a los miembros de la clase base. Si no se especifica un acceso a la clase base, C++ supone que su tipo de herencia es privado. - Derivación pública (public). Todos los miembros public y protected de la clase base son accesibles en la clase derivada, mientras que los miembros private de la clase base son siempre inaccesibles en la clase derivada. - Derivación privada (private). Todos los miembros de la clase base se comportan como miembros privados de la clase derivada. Esto significa que los miembros public y protected de la clase base no son accesibles más que por las funciones miembro de la clase derivada. Los miembros privados de la clase siguen siendo inaccesibles desde la clase derivada. - Derivación protegida (protected). Todos los miembros public y protected de la clase base se comportan como miembros protected de la clase derivada. Estos miembros no son, pues, accesibles al programa exterior, pero las clases que se deriven a continuación podrán acceder normalmente a estos miembros (datos o funciones). 17
  • 20. Programación Orientada a Objetos 10.7. Constructores y destructores en herencia Una clase derivada puede tener tanto constructores como destructores, aunque tiene el problema adicional de que la clase base puede tomar ambas funciones miembro especiales. Un constructor o destructor definido en la clase base debe estar coordinado con los encontrados en una clase derivada. Igualmente importante es el movimiento de valores de los miembros de la clase derivada a los miembros que se encuentran en la base. En particular, se debe considerar cómo el constructor de la clase base recibe valores de la clase derivada para crear el objeto completo. Si un constructor se define tanto para la clase base como para la clase derivada, C++ llama primero al constructor base. Después que el constructor de la base termina sus tareas, C++ ejecuta el constructor derivado. Cuando una clase base define un constructor, éste se debe llamar durante la creación de cada instancia de una clase derivada, para garantizar la buena inicialización de los datos miembro que la clase derivada hereda de la clase base. En este caso la clase derivada debe definir a su vez un constructor que llama al constructor de la clase base proporcionándole los argumentos requeridos. Un constructor de una clase derivada debe utilizar un mecanismo de pasar aquellos argumentos requeridos por el correspondiente constructor de la clase base. derivada::derivada(tipo1 x, tipo2 y):base (x,y) {...} Otro aspecto importante que es necesario considerar es el orden en el que el compilador C++ inicializa las clases base de una clase derivada. Cuando El compilador C++ inicializa una instancia de una clase derivada, tiene que inicializar todas las clases base primero. Por definición, un destructor de clases no toma parámetros. Al contrario que los constructores, una función destructor de una clase derivada se ejecuta antes que el destructor de la clase base. 10.8. Redefinición de funciones miembro heredadas Se pueden utilizar funciones miembro en una clase derivada que tengan el mismo nombre que otra de una clase base. La redefinición de funciones se realiza mediante funciones miembro sobrecargadas en la clase derivada. Una función miembro redefinida oculta todas las funciones miembro heredadas del mismo nombre. Por tanto cuando en la clase base y en la clase derivada hay una función con el mismo nombre en las dos, se ejecuta la función de la clase derivada. 10.9. Herencia múltiple Es la propiedad con la cual una clase derivada puede tener más de una clase base. Es más adecuada para definir objetos que son compuestos, por naturaleza, tales como un registro personal, un objeto gráfico. Sólo es una extensión de la sintaxis de la clase derivada. Introduce una cierta complejidad en el lenguaje y el compilador, pero proporciona grandes beneficios. class ejemplo: private base1, private base2 {...}; La aplicación de clases base múltiples introduce un conjunto de ambigüedades a los programas C++. Una de las más comunes se da cuando dos clases base tienen funciones con el mismo nombre, y sin embargo, una clase derivada de ambas no tiene ninguna función con ese nombre. ¿ Cómo acceden los objetos de la clase derivada a la función correcta de la clase 18
  • 21. Programación Orientada a Objetos base ? El nombre de la función no es suficiente, ya que el compilador no puede deducir cuál de las dos funciones es la invocada. Si se tiene una clase C que se deriva de dos clases base A y B, ambas con una función mostrar() y se define un objeto de la clase C: C objetoC, la manera de resolver la ambigüedad es utilizando el operador de resolución de ámbito: objetoC.A::mostrar(); //se refiere a la versión de //mostrar() de la clase A objetoC.B::mostrar(); //se refiere a la versión de //mostrar() de la clase B 10.10. Constructores y destructores en herencia múltiple El uso de funciones constructor y destructor en clases derivadas es más complejo que en una clase simple. Al crear clases derivadas con una sola clase base, se observa que el constructor de la clase base se llama siempre antes que el constructor de la clase derivada. Además se dispone de un mecanismo para pasar los valores de los parámetros necesarios al constructor base desde el constructor de la clase derivada. Así, la sentencia siguiente pasa el puntero a carácter x y el valor del entero y a la clase base: derivada (char *x, int y, double z): base(x,y) Este método se expande para efectuar más de una clase base.La sentencia: derivada (char *x,int y, double z): base1(x),base2(y) Llama al constructor base1 y pasa el valor de cadena de caracteres x y al constructor base2 le proporciona un valor entero y. Como con la herencia simple, los constructores de la clase base se llaman antes de que se ejecuten al constructor de la clase derivada. Los constructores se llaman en el orden en que se declaran las clases base. De modo similar, las relaciones entre el destructor de la clase derivada y el destructor de la clase base se mantiene. El destructor derivado se llama antes de que se llame a los destructores de cualquier base. Los destructores de las clases base se llaman en orden inverso al orden en que los objetos base se crearon. 10.11. Herencia repetida La primera regla de la herencia múltiple es que una clase derivada no puede heredar más de una vez de una sola clase, al menos no directamente. Sin embargo, es posible que una clase se pueda derivar dos o más veces por caminos distintos, de modo que se puede reprtir una clase. La propiedad de recibir por herencia una misma clase más de una vez se conoce como herencia repetida. 10.12. Clases base virtuales Una clase base virtual es una clase que es compartida por otras clases base con independencia del número de veces que esta clase se produce en la jerarquía de derivación. Suponer , por ejemplo, que la clase T se deriva de las clases C y D cada una de las cuales se deriva de la clase A. Esto significa que la clase T tiene dos instancias de A en su jerarquía de derivación. C++ permite instancias múltiples de la misma clase base. Sin embargo, si sólo se desea una instancia de la clase A para la clase T, entonces se debe declarar A como una clase base virtual. 19
  • 22. Programación Orientada a Objetos Las clases base virtuales proporcionan un método de anular el mecanismo de herencia múltiple, permitiendo especificar una clase que es una clase base compartida. Una clase derivada puede tener instancias virtuales y no virtuales de la misma clase base. 11. Polimorfismo En un sentido literal, significa la cualidad de tener más de una forma. En el contexto de POO, el polimorfismo se refiere al hecho de que una misma operación puede tener diferente comportamiento en diferentes objetos. Por ejemplo, consideremos la operación sumar. El operador + realiza la suma de dos números de diferente tipo. Además se puede definir la operación de sumar dos cadenas mediante el operador suma. 12. Ejemplo Punto -x : double = 0 -y : double = 0 +ponX(entrada _x : double) +ponY(entrada _y : double) +dameX() : double +dameY() : double +area() : double +perimetro() : double Rectangulo Circulo -lh : double = 10 -lv : double = 10 -radio : double = 10 +ponLH(entrada _lh : double) +ponRadio(entrada _r : double) +dameLV() : double +dameRadio() : double +ponLV(entrada _lv : double) +dameLH() : double 20
  • 23. Programación Orientada a Objetos 13. Operadores 13.1. Operadores especiales de C++ :: Resolución de ámbito (o alcance) Indirección (eliminación de referencia directa) un puntero a un miembro de una .* clase Indirección (eliminación de referencia directa) un puntero a un miembro de una ->* clase new Asigna (inicializa) almacenamiento dinámico delete Libera almacenamiento asignado por new 13.2. Operador de resolución de ámbito C es un lenguaje estructurado por bloques. C++ hereda la misma noción de bloque y ámbito. En ambos lenguajes, el mismo identificador se puede usar para referenciar a objetos diferentes. Un uso en un bloque interno oculta el uso externo del mismo nombre. C++ introduce el operador de resolución de ámbito o de alcance. El operador :: se utiliza para acceder a un elemento oculto en el ámbito actual. Su sintaxis es :: variable Ejemplo: #include <iostream.h> int a; void main() { float a; a=1.5; ::a=2; cout << quot;a local quot; << a << quot;nquot;; cout << quot;a global quot; << ::a << quot;nquot;; } Este programa visualiza: a local 1.5 a global 2 Este operador se utilizará también en la gestión de clases. 13.3. Asignación dinámica de memoria: new y delete En C la asignación dinámica de memoria se manipula con las funciones malloc() y free(). En C++ se define un método de hacer asignación dinámica utilizando los operadores new y delete. En C: void main() { int *z; 21
  • 24. Programación Orientada a Objetos z= (int*) malloc(sizeof(int)); *z=342; printf(quot;%dnquot;,*z) free(z); } En C++: void main() { int *z=new int; *z=342; cout << z; delete z; } El operador new está disponible directamente en C++, de modo que no se necesita utilizar ningún archivo de cabecera; new se puede utilizar con dos formatos: new tipo // asigna un único elemento new tipo[num_eltos] // signa un array Si la cantidad de memoria solicitada no está disponible, el operador new proporciona el valor 0. El operador delete libera la memoria signada con new. delete variable delete [n] variable new es superior a malloc por tres razones: 1. new conoce cuánta memoria se asigna a cada tipo de variable. 2. malloc() debe indicar cuánta memoria asignar. 3. new hace que se llame a un constructor para el objeto asignado y malloc no puede. delete produce una llamada al destructor en este orden: 1. Se llama al destructor 2. Se libera memoria delete es más seguro que free() ya que protege de intentar liberar memoria apuntada por un puntero nulo. 14. Entradas y salidas básicas 14.1. La biblioteca iostream C++ proporciona una nueva biblioteca de funciones que realizan operaciones de E/S: la biblioteca iostream. Esta biblioteca es una implementación orientada a objetos y está basada, al igual que stdio, en el concepto de flujos. Cuando se introducen caracteres desde el teclado, puede pensarse en caracteres que fluyen desde el teclado a las estructuras de datos del programa. Cuando se escribe en un archivo, se piensa en un flujo de bytes que van del programa al disco. Para acceder a la biblioteca iostream se debe incluir el archivo iostream.h. Este archivo contiene información de diferentes funciones de E/S. Define también los objetos cin y cout. 22
  • 25. Programación Orientada a Objetos 14.2. Manipuladores de salida La biblioteca iostream define varios operadores particulares, llamados manipuladores, que le permiten controlar precisamente, el formato de los datos visualizados. Situando un manipulador en la cadena de operadores <<, se puede modificar el estado del flujo. Una característica importante de un flujo que debe tratar con valores numéricos es la base de los números. Hay tres manipuladores (dec, hex y oct) para controlar la situación. La base por omisión es 10 y por tanto sólo será necesario indicar dec cuando se haya fijado la base a otro valor: cout <<oct<<x<<endl; cout <<dec<<x<<endl; Los manipuladores que toman argumentos se declaran en iomanip.h, el resto en iostream.h. Manipuladores Aplicación Descripción dec cout<<dec<<x; Conversión a decimal cin>>dec>>x; hex out<<hex<<x; conversión a hexadecimal cin>>hex>>x; oct cout<<oct<<x; Conversión a octal cin>>oct>>x; ws cin>>ws; Salta espacios en la entrada endl cout<<endl; Envía carácter fin de línea flush cout<<flush; Limpia el buffer setfill(int) cout<<setfill('*'; Fija el carácter de rellenado setprecision(int) cout<<setprecision(6); Fija la conversión en coma flotante al nº de dígitos especificado setw(int) cout<<setw(6)<<x; Fija la anchura cin>>setw(10)>>x; Con setw() los valores numéricos se justifican a derechas y los datos carácter a izquierdas. La información de la justificación de la salida se almacena en un modelo o patrón de bits de una clase llamada ios, que constituye la base de todas las clases de flujos. Puede establecer o reinicializar bits específicos utilizando los manipuladores setiosflags() y resetiosflags() respectivamente. Para utilizar cualquiera de los indicadores de formato hay que insertar el manipulador setiosflags() con el nombre del indicador como argumento. Hay que utilizar resetiosflags() con el mismo argumento para invertir el estado del formato antes de utilizar el manipulador setiosflags(). Indicador Significado del indicador activado ios::left Justifica la salida a la izquierda ios::right Justifica la salida a la derecha ios::scientific Utiliza notación científica para números de coma flotante ios::fixed Utiliza notación decimal para números de coma flotante ios::dec Utiliza notación decimal para enteros ios::hex Utiliza notación hexadecimal para enteros ios::oct Utiliza notación octal para enteros ios::showpos Muestra un signo positivo cuando se visualizan valores positivos 23
  • 26. Programación Orientada a Objetos 15. Compilación separada Un programa C++ consta de uno o más archivos fuente que se compilan y enlazan juntos para formar un programa ejecutable. La mayoría de las bibliotecas contienen un número significativo de funciones y variables. Para ahorrar trabajo y asegurar la consistencia cuando se hacen declaraciones externas de estos elementos, C++ utiliza un dispositivo denominado archivo de cabecera. Un archivo de cabecera es un archivo que contiene las declaraciones externas de una biblioteca. Estos archivos tienen extensión .h. Ejemplo: archivo max.h int max(int,int); //prototipo de la función – declaración de la función archivo maximo.cpp int max(int x, int y) //definición de la función o implementación de la función { if (x>y) return(x); return(y); } archivo principal.cpp #include <iostream.h> #include quot;max.hquot; void main() { int a=5,b=6; cout<<quot;mayor quot;<<max(a,b); } 24