Você está na página 1de 32

Tema 2.

Clases
Implementacin de una clase
Descripcin de una clase en C++ Elementos pblicos y privados Acceso directo a atributos Clases amigas Implementacin de las operaciones Funciones miembro inline Organizacin del cdigo en C++

Inicializacin y finalizacin de clases


Constructores Destructores

Implementacin de clases
Partiendo del diseo orientado a objetos de un sistema, la tarea ms bsica a la que nos enfrentamos durante la fase de implementacin es la traslacin de cada clase al al lenguaje de programacin orientado a objetos que estemos utilizando.

Cuenta nmero: String titular: String saldo: Integer inters_anual: Real ingreso (cantidad: Integer) reintegro (cantidad: Integer) ingreso_interes () esta_en_rojos (): Boolean ver_saldo (): Integer

Ejemplo: un objeto que representa las cuentas en una aplicacin de gestin bancaria.

Fichero cuenta.hpp

class Cuenta { char numero[20]; char titular[80]; long int saldo; float interes; public:

Atributos. (Variables miembro)

void ingreso (long int cantidad); void reintegro (long int cantidad); void ingreso_interes (void); Operaciones int esta_en_rojos (void); (Funciones miembro) long int ver_saldo (void); };

Elementos pblicos y privados


Seccin public (pblica): delimita los miembros accesibles desde el exterior de la clase. Seccin private (privada): protege los elementos cuyo acceso desde el exterior no est permitido. Por defecto todos los miembros son privados. class Cuenta { private: char numero[20]; char titular[80]; long int saldo; float interes; public:

Seccin privada Seccin pblica

void ingreso (long int cantidad); void reintegro (long int cantidad); void ingreso_interes (void); int esta_en_rojos (void); long int ver_saldo (void);
};

Funciones miembro privadas

class Cuenta { char numero[20]; char titular[80]; long int saldo; float interes;

Funcin miembro privada auxiliar (usada por ingreso y reintegro).

void modificar_saldo (long int cantidad);

public:
void ingreso (long int cantidad); void reintegro (long int cantidad); void ingreso_interes (void); int esta_en_rojos (void); long int ver_saldo (void);

};

Acceso a atributos. Atributos pblicos


En muchas ocasiones, es necesario que el valor de un atributo sea visible desde el exterior para lectura, como por ejemplo el saldo de una cuenta. class Cuenta { char numero[20]; char titular[80]; float interes; public: long int saldo; Situar una variable miembro en la seccin public es posible pero poco recomendable: - El atributo puede ser modificado desde el exterior tambin. - Se establece una dependencia entre el exterior y la representacin interna de la clase.

void ingreso (long int cantidad); void reintegro (long int cantidad); void ingreso_interes (void); int esta_en_rojos (void); };

Acceso a atributos. Funciones miembro de acceso


En muchas ocasiones, es necesario que el valor de un atributo sea visible desde el exterior para lectura, como por ejemplo el saldo de una cuenta. class Cuenta { char numero[20]; char titular[80]; long int saldo; float interes; public: void ingreso (long int cantidad); void reintegro (long int cantidad); void ingreso_interes (void); int esta_en_rojos (void); long int ver_saldo (void); };

Es mucho ms seguro el uso de funciones miembro de acceso a las variables miembro, aunque puede suponer una pequea penalizacin en el tiempo de acceso necesario.

Clases amigas
A veces dos clases estn tan ntimamente relacionadas que una requiere acceso total a varios atributos y operaciones privados de la otra. Este acceso puede realizarse proporcionando las operaciones pblicas necesarias, pero esto puede resultar engorroso e innecesario, pues slo esta clase requiere estas operaciones. La clase InformeCuenta realiza un informe impreso del estado de una Cuenta con todos sus datos. Para ello necesita acceder a todos los atributos de la clase, pero stos son privados y no existe en todos los casos operaciones para obtener su valor. Solucin: hacer la clase InformeCuenta amiga de Cuenta para que tenga acceso completo a sus atributos. Hacer una clase amiga de otra es permitir selectivamente la violacin de las reglas de ocultacin de informacin.

InformeCuenta ttulo: Cadena (120) fecha: Fecha Imprimir (c: Cuenta)

class Cuenta { char numero[20]; char titular[80]; long int saldo; float interes; public: friend class InformeCuenta;

A partir de ahora la clase InformeCuenta es amiga de Cuenta y tiene acceso completo a sus atributos privados

void ingreso (long int cantidad); void reintegro (long int cantidad); void ingreso_interes (void); int esta_en_rojos (void); long int ver_saldo (void);
};

La declaracin de clases amigas debe realizarse con moderacin y slo en casos en que est plenamente justificado.

Implementacin de las operaciones


Dependiendo del lenguaje de programacin, la implementacin de las operaciones se realiza en el mismo sitio que la interfaz de la clase (Java, Eiffel) o en ficheros separados, como en C++:

Fichero cuenta.cpp
void Cuenta::ingreso (long int cantidad) { saldo += cantidad; }

void Cuenta::reintegro (long int cantidad) { saldo -= cantidad; Calificador de clase. Indica la } clase que contiene la funcin miembro

void Cuenta::ingreso_interes (void) { saldo += saldo * interes / 100; El acceso a una variable de clase } es directo, como si se tratara de una variable local definida en int Cuenta::esta_en_rojos (void) cada una de las funciones { miembro. Es equivalente a: return saldo < 0; ::saldo -> Indicacin explcita de } que se trata de una variable de clase. long int Cuenta::ver_saldo (void) { Cuenta::saldo -> Igual que la return saldo; forma anterior pero indicando } cual es la clase a la que pertenece.

Funciones inline (en lnea).

Generacin de cdigo para una llamada a una funcin miembro ordinaria ...

Generacin de cdigo para una llamada a una funcin miembro ordinaria ...

MOV B, A CALL ver_saldo SUM B, 30H

MOV B, A MOV AX, SALDO SUM B, 30H

... Cuenta::ver_saldo MOV AX , SALDO PUSH AX RETURN

...

Una llamada a una funcin miembro inline es mucho ms rpida ya que se elimina el salto, el retorno y introduccin en la pila del resultado

class Cuenta { char numero[20]; char titular[80]; long int saldo; float interes; public: void ingreso (long int cantidad); void reintegro (long int cantidad); void ingreso_interes (void); int esta_en_rojos (void) { return saldo < 0; } long int ver_saldo (void) { return saldo; } };

Las funciones inline se implementan en la interfaz de la clase.

Organizacin del cdigo en C++


// ----------------------------------------------------------// Cuenta.hpp - Interfaz de la clase Cuenta // ----------------------------------------------------------#ifndef CUENTA_HPP #define CUENTA_HPP class Cuenta { char numero[20]; // Variables miembro char titular[80]; long int saldo; float interes; public: void ingreso (long int cantidad); // Funciones miembro void reintegro (long int cantidad); void ingreso_interes (void); int esta_en_rojos (void) { return saldo < 0; } long int ver_saldo (void) { return saldo; } }; #endif // Fin de Cuenta.hpp -----------------------------------------

// ----------------------------------------------------------// Cuenta.cpp - Implementacin de la clase Cuenta // ----------------------------------------------------------#include "cuenta.hpp" void Cuenta::ingreso (long int cantidad) { saldo += cantidad; }

void Cuenta::reintegro (long int cantidad) { saldo -= cantidad; }


void Cuenta::ingreso_interes (void) { saldo += saldo * interes / 100; } // Fin de Cuenta.cpp -----------------------------------------

Inicializacin de una clase


Ya sabemos como definir atributos en una clase, pero que valor inicial tienen estos atributos cuando en el momento de la creacin de un objeto de dicha clase?.

Es necesario poder inicializar un objeto antes de comenzar a trabajar con l. Las tareas tpicas en la inicializacin son:
Inicializacin de atributos Asignacin de memoria dinmica Apertura de archivos

Una primera solucin: definir una operacin de inicializacin de la clase.

void Cuenta::inicializar (char *anumero, char *atitular, long int asaldo, float ainteres) { strcpy (numero, anumero); strcpy (titular, atitular); saldo = asaldo; interes = ainteres; }

Esta no es una solucin limpia: - Obliga al usuario a conocer cual es la funcin miembro de inicializacin del objeto, que puede tener muchos nombres: inicializa, inicializar, nueva, crear. - Si el usuario olvida llamar a la funcin miembro de inicializacin tras crear el objeto surgirn muchos problemas...

La programacin orientada a objetos proporciona un medio de inicializacin ms normalizado y mucho ms seguro: los constructores. Un constructor es una operacin especial de la clase que se llama automticamente durante la creacin del objeto. En C++ es fcilmente reconocible porque tiene el mismo nombre que la clase. class Cuenta { char numero[20]; char titular[80]; long int saldo; float interes; public: Cuenta (char *anumero, char *atitular, long int asaldo, float ainteres); // Constructor void ingreso (long int cantidad); void reintegro (long int cantidad); void ingreso_interes (void); int esta_en_rojos (void) { return saldo < 0; } long int ver_saldo (void) { return saldo; } };

La implementacin del constructor de nuestra clase sera la siguiente: Cuenta::Cuenta (char *anumero, char *atitular, long int asaldo, float ainteres) { strcpy (numero, anumero); strcpy (titular, atitular); saldo = asaldo; interes = ainteres; } Mltiples constructores Muchas veces resulta muy interesante definir varios mtodos de inicializacin para una clase. Por ejemplo, una clase Imagen puede ser inicializada de varias formas: - Crear una imagen vaca, indicando el tamao en pixels y el nmero de colores. - Crear una imagen recuperandola desde un fichero en disco, dado el nombre del mismo. - Crear una imagen mediante una operacin pegndola desde el portapapeles del sistema.

class Cuenta { char numero[20]; char titular[80]; long int saldo; float interes;

La sobrecarga de funciones de C++ permite que puedan definirse varios constructores para una clase, siempre y cuando se diferencien al menos en el tipo o nmero de argumentos.

public: // Constructor para cualquier tipo de cuentas Cuenta (char *anumero, char *atitular, long int asaldo, float ainteres); // Constructor para cuentas corrientes (interes = 1) Cuenta (char *anumero, char *atitular, long int asaldo); void ingreso (long int cantidad); void reintegro (long int cantidad); void ingreso_interes (void); int esta_en_rojos (void) { return saldo < 0; } long int ver_saldo (void) { return saldo; } };

La implementacin del segundo constructor sera: Cuenta::Cuenta (char *anumero, char *atitular, long int asaldo) { strcpy (numero, anumero); strcpy (titular, atitular); saldo = asaldo; interes = 1; } Vamos a aadir un tercer constructor para leer los datos de la cuenta desde un fichero: class Cuenta { char numero[20]; char titular[80]; long int saldo; float interes; public: // Constructor para nuevas cuentas de cualquier tipo Cuenta (char *anumero, char *atitular, long int asaldo, float ainteres);

// Constructor para nuevas cuentas corrientes (interes = 1) Cuenta (char *anumero, char *atitular, long int asaldo);

// Constructor para cuentas ya existentes, almacenadas en disco


Cuenta (char *anumero); void ingreso (long int cantidad); void reintegro (long int cantidad); void ingreso_interes (void); int esta_en_rojos (void) { return saldo < 0; } long int ver_saldo (void) { return saldo; } }; Cuenta::Cuenta (char *anumero) { char nombref[80]; strcpy (numero, anumero);

strcpy (nombref, anumero); strcat (nombref, ".cnt");

// Abrir el fichero de la cuenta ifstream in (nombref); if (!in) exit;


// Leer los valores de las variables miembro getline (in, numero); getline (in, titular); in >> saldo; in >> interes;

Una limitacin especialmente grave de C++ y Java es que no pueden definirse dos constructores que reciban los mismos parmetros aunque signifiquen cosas distintas. Por ejemplo, no podramos aadir un constructor para cuentas de ahorro (con un inters fijo al 8%): Cuenta::Cuenta (char *anumero, char *atitular, long int asaldo) { strcpy (numero, anumero); strcpy (titular, atitular); saldo = asaldo; interes = 8; } Los parmetros coinciden con los del constructor para cuentas corrientes, por tanto el compilador no puede distinguir entre ambas funciones y producir un error de compilacin.

En el lenguaje Eiffel esto es posible, ya que cada constructor puede tener un nombre distinto: -- Constructor general de la clase Cuenta crear (anumero, atitular: STRING; asaldo: INTEGER; ainteres: REAL) is do ... End -- Constructor para cuentas corrientes (interes = 1) crear_corriente (anumero, atitular: STRING; asaldo: INTEGER) is do ... end -- Constructor para cuentas de ahorro (interes = 8) crear_ahorro (anumero, atitular: STRING; asaldo: INTEGER) is do ... end

Cuando un argumento puede tomar o no un valor por defecto pueden utilizarse argumento por omisin. El nmero de argumentos por defecto puede variar, pero siempre quedar agrupados al final de la lista de parmetros. En el siguiente constructor de la clase cuenta, el ltimo argumento posee un valor por omisin. A una cuenta que no se le proporcione un inters de forma explcita, quedar con el valor del argumento por omisin. Cuenta::Cuenta (char *anumero, char *atitular, long int asaldo, ainteres = 1) { strcpy (numero, anumero); strcpy (titular, atitular); saldo = asaldo; interes = ainteres; }

Constructores por defecto Un constructor por defecto u omisin es aquel que no requiere argumentos. La lista de argumentos es o bien vaca, o todos los argumentos tienen valores por omisin asignados a ellos. Se utilizan para poder inicializar objetos de alguna manera, aunque sus atributos no posean los valores definitivos. Argumentos con valores por omisin: class fecha{ int dd, mm, aa; public: fecha(int d=0; int m=0; int a=0):dd(d),mm(m),aa(a){} void escribir(){cout<<dd<<"/"<<mm<<"/"<<aa<<endl;} }

Lista de argumentos vaca


class fecha{ int dd, mm, aa; public: fecha():dd(0),mm(0),aa(0){}; void escribir(){cout<<dd<<"/"<<mm<<"/"<<aa<<endl;} }

Constructor copia Un constructor copia es aquel que sirve para crear un objeto exactamente igual que otro. Cuenta::Cuenta (Cuenta& c) { strcpy (numero, c.numero); strcpy (titular, c.titular); saldo = c.saldo; interes = c.interes; }

El compilador proporciona siempre un constructor copia por defecto. Este constructor simplemente copia los valores de los atributos del objeto que se pasa como argumento. Cuando esto no sea suficiente, proporcionaremos un constructor copia con asignaciones vlidas

Finalizacin de una clase


De manera anloga a la inicializacin, muchas veces es necesario realizar ciertas tareas antes de la destruccin de un objeto de una clase tras su uso:
Liberacin de memoria dinmica asignada durante la vida del objeto. Cierre de ficheros, liberacin en general de cualquier recurso del sistema. Salvar el contenido del objeto de manera permanente en disco o en una base de datos.

Podra usarse nuevamente una operacin como destruye, finaliza o libera para este fn, pero los inconvenientes seran los mismos que los existentes en el caso de la inicializacin. Los lenguajes orientados a objetos proporcionan un tipo de operaciones especiales denominados destructores de la clase, que se llaman automticamente cuando un objeto es destruido.

Al contrario que en el caso de los constructores, normalmente solo existe un nico destructor. En C++ el destructor tiene el mismo nombre que la clase, precedido por el carcter ~ (ASCII 126) y nunca tiene argumentos en la llamada. // Un Array dinmico para enteros muy simple. class ArrayIntDin { int *mem; long int tam; public: // Constructor, asignacin de memoria dinmica // para el buffer del array ArrayIntDin (long int atam) { mem = new int[tam = atam]; } // Destructor del buffer ~ArrayIntDin () { delete mem; } // Lectura y escritura en el buffer int leer (long int pos) { return mem[pos]; } void escribir (long int pos, int valor) { mem[pos] = valor; }

};

Tras operar con una cuenta, sera necesario que se salvara de manera permanente en disco. As cuando se vuelva a recuperar, su saldo y dems caractersticas se mantendrn justo como estaban tras la ltima actualizacin: class Cuenta { char numero[20]; char titular[80]; long int saldo; float interes; public: // Constructores Cuenta (char *anumero, char *atitular, long int asaldo, float ainteres); Cuenta (char *anumero, char *atitular, long int asaldo); Cuenta (char *anumero); // Destructor de la cuenta. Salva el estado de la cuenta en disco ~Cuenta (); void ingreso (long int cantidad); // Operaciones de la clase void reintegro (long int cantidad); void ingreso_interes (void); int esta_en_rojos (void) { return saldo < 0; } long int ver_saldo (void) { return saldo; } };

Cuenta::~Cuenta () { char nombref[80]; strcpy (nombref, numero); strcat (nombref, ".cnt"); // Abrir el fichero de la cuenta para escritura // (Obviamos la comprobacin de errores) ofstream out (nombref); // Escribir los valores de las variables miembro out << titular <<endl<< saldo <<endl<< interes <<endl; }

Si una clase no requiere ninguna finalizacin en especial, no es necesario incluir un destructor sin cdigo en la interfaz de la clase:

~Cuenta() {}

Você também pode gostar