28
MANUAL DE PROGRAMACION EN C++ 127 INTRODUCCION La solución integral de los problemas de ingeniería necesita competencias en diferentes áreas del conocimiento, y en este caso particular, el aprendizaje de herramientas eficientes para el desarrollo de software específico, por parte del estudiante, reviste gran importancia. Las soluciones de software en la actualidad ofrecen gran versatilidad frente a las soluciones físicas, dadas sus características de escalabilidad y evolución. La Programación Orientada a Objetos se hace pertinente para ampliar la visión de los estudiantes, como programadores, con conceptos de mayor dimensión y abstracción que les permitan resolver problemas con mayor grado de complejidad y más cercanos a la realidad. De esta forma un estudiante adquiere habilidades para abordar problemas de forma integral y puede aplicar el desarrollo e implementación de software en cualquier área, incluso no relacionada con ingeniería. El presente documento busca exponer de forma clara los principales conceptos relacionados con la Programación Orientada a Objetos y mostrar sus principales aplicaciones, así como ilustrar con ejemplos aplicados a problemas de ingeniería, sus conocidas ventajas frente a otras técnicas y metodologías de programación.

OOP Basics

  • Upload
    hmurcia

  • View
    230

  • Download
    0

Embed Size (px)

DESCRIPTION

OOP Basics

Citation preview

Page 1: OOP Basics

MANUAL DE PROGRAMACION EN C++

127

INTRODUCCION

La solución integral de los problemas de ingeniería necesita competencias en diferentes áreas del

conocimiento, y en este caso particular, el aprendizaje de herramientas eficientes para el

desarrollo de software específico, por parte del estudiante, reviste gran importancia. Las

soluciones de software en la actualidad ofrecen gran versatilidad frente a las soluciones físicas,

dadas sus características de escalabilidad y evolución.

La Programación Orientada a Objetos se hace pertinente para ampliar la visión de los estudiantes,

como programadores, con conceptos de mayor dimensión y abstracción que les permitan resolver

problemas con mayor grado de complejidad y más cercanos a la realidad. De esta forma un

estudiante adquiere habilidades para abordar problemas de forma integral y puede aplicar el

desarrollo e implementación de software en cualquier área, incluso no relacionada con ingeniería.

El presente documento busca exponer de forma clara los principales conceptos relacionados con

la Programación Orientada a Objetos y mostrar sus principales aplicaciones, así como ilustrar con

ejemplos aplicados a problemas de ingeniería, sus conocidas ventajas frente a otras técnicas y

metodologías de programación.

Page 2: OOP Basics

UNIVERSIDAD MILITAR “NUEVA GRANADA” CENTRO DE SISTEMAS

128

OBJETIVOS

General

Presentar los conceptos y aplicaciones de la Programación Orientada a Objetos (POO), las técnicas

de implementación de esta metodología en lenguaje C++ y sus ventajas en el desarrollo de

software de aplicación específica.

Específicos

- Comprender las nociones de la abstracción de datos a través del estudio de los Tipos de Datos

Abstractos (TDA) más utilizados.

- Presentar los conceptos fundamentales de la POO y su implementación en lenguaje C++.

- Presentar la herencia y sus principales características, como una forma de reutilización de

software.

- Estudiar la utilización de apuntadores, como una de las características más poderosas del

lenguaje C++.

- Presentar las técnicas para crear y manipular estructuras dinámicas de datos.

Page 3: OOP Basics

MANUAL DE PROGRAMACION EN C++

129

9 CONCEPTOS BÁSICOS DE PROGRAMACIÓN ORIENTADA A OBJETOS

Introducción

En la vida diaria los seres humanos piensan en objetos. La Programación Orientada a Objetos

(POO) es una forma de realizar programas que utiliza, precisamente, los objetos como su

elemento de construcción fundamental. En esta unidad modular se presentan los conceptos

básicos de la POO y su implementación en el lenguaje C++.

Objetivo General

Presentar los conceptos fundamentales de la POO y su implementación en lenguaje C++.

Objetivos específicos

- Conocer los fundamentos de la POO en el lenguaje C++.

- Aprender a diseñar y utilizar clases y objetos en C++.

- Conocer las principales características de la implementación de clases en el lenguaje C++.

9.1 CONCEPTOS FUNDAMENTALES DE POO

Pensar en objetos es pensar como lo hacemos en la vida real. Si usted mira a su alrededor lo que

ve son objetos, personas, animales, libros, computadores, muebles, edificios, etc. La Programación

Orientada a Objetos (POO) es un estilo de programación que emplea los objetos como

componentes fundamentales para la construcción de programas. Es decir, realiza un modelado de

objetos reales, sus características y comportamiento.

Objetos

Un objeto es una representación detallada, concreta y particular de algo. Corresponden a los

objetos reales del mundo que nos rodea, o a objetos internos del programa. Vistos de esta

manera, son tipos abstractos de datos que están conformados por atributos y funciones que

actúan sobre esos atributos. Es decir, un objeto es una unidad que contiene datos y las funciones

que operan sobre esos datos. A los elementos de un objeto se les conoce como miembros; las

funciones que operan sobre los datos se denominan “funciones miembro” y los datos se

denominan miembros datos.

Page 4: OOP Basics

UNIVERSIDAD MILITAR “NUEVA GRANADA” CENTRO DE SISTEMAS

130

Los objetos pueden se cualquier entidad del mundo real:

- Objetos físicos:

Carros

Barcos

Personas

Animales, etc.

- Tipos de datos definidos por el usuario

Hora del día

Fraccionarios

En C++ un programa consta de objetos. Los objetos de un programa se comunican entre sí

mediante el paso o envío de mensajes (acciones que debe ejecutar el objeto).

Adicionalmente, un objeto tiene una identidad que determina su estado y su comportamiento

particular en un momento dado. Dicha identidad permite diferenciar objetos entre sí. Por otro

lado, el estado de un objeto es el conjunto de valores concretos que lo caracterizan en un

momento dado.

Mensajes

Los objetos de un programa se comunican entre sí mediante el paso o envío de mensajes. Estos

mensajes producen la ejecución de las funciones de los objetos. Sin embargo, los objetos se

ocultan información entre sí, es decir, en general un objeto no sabe cómo está implementado otro

objeto diferente.

Clases

La definición de objeto nos lleva a una de los conceptos fundamentales de la POO que es el de

clase. Una clase se puede considerar como un patrón para construir objetos, es decir, son tipos de

datos definidos por el programador, quien determina las estructuras de datos y las operaciones

asociadas con ese tipo.

Page 5: OOP Basics

MANUAL DE PROGRAMACION EN C++

131

En C++, un objeto es sólo un tipo de variable de una clase determinada. Cada vez que se construye

un objeto de una clase, se crea una instancia de esa clase. Así como a una instancia del tipo

predefinido double se le llama variable, una instancia de una clase es el objeto. Por consiguiente,

una clase define las propiedades y comportamiento de un tipo de objeto concreto. La

instanciación es la lectura de estas definiciones y la creación de un objeto a partir de ellas.

Es importante diferenciar entre objetos y clases, una clase es una colección de objetos similares y

un objeto es una instancia de una definición de una clase. La clase es simplemente una

declaración, no tiene asociado ningún objeto, de modo que no puede recibir mensajes ni

procesarlos, esto únicamente lo hacen los objetos.

Herencia

La herencia es la propiedad que permite la creación de clases a partir de clases que ya existen, las

cuales heredan características y funciones de las clases existentes. En C++ la clase original se llama

clase base; y las clases definidas a partir de dicha clase base se denominan clases derivadas. Las

clases derivadas pueden heredar atributos de la base pero también pueden adicionar sus propias

características y funciones.

La herencia produce relaciones jerárquicas entre las clases, pues existen clases hijas y padres.

Dependiendo del tipo de herencia existen clases que reciben características de una sola clase

(herencia simple) y otras clases que reciben atributos de más de una clase base (herencia

múltiple).

Lenguaje Unificado de Modelado (UML)

El UML es un lenguaje gráfico utilizado para representar los programas orientados a objetos de

manera visual. Representa las relaciones entre clases bases y clases derivadas así como entre

objetos.

Polimorfismo

Es una característica de la POO que describe el hecho de que una función puede tener un

comportamiento diferente dependiendo del tipo de objeto sobre el cual esté actuando. Por

Page 6: OOP Basics

UNIVERSIDAD MILITAR “NUEVA GRANADA” CENTRO DE SISTEMAS

132

ejemplo, se puede definir la función multiplicar como la multiplicación entre dos números

escalares así como la multiplicación entre dos matrices.

Programa orientado a objetos

Un programa orientado a objetos se puede ver como un conjunto de clases. Debe tener una

función principal que se encarga de la creación de los objetos y comienza la ejecución de las

funciones de dichos objetos.

La ejecución de un programa orientado a objetos consta fundamentalmente de tres pasos:

1. Creación de los objetos en el momento en el que se necesiten.

2. Envío y recepción de mensajes entre objetos.

3. Eliminación de los objetos que ya no son necesarios.

9.2 CLASES

La programación orientada a objetos encapsula atributos y operaciones en clases. Una clase es un

tipo abstracto de dato definido por el usuario que está conformado por atributos y operaciones.

En C++ los atributos son implementados como datos mientras que las operaciones son funciones.

Así como un plano permite la construcción de varias casas, a partir de una clase se pueden crear

varios objetos. Por consiguiente, los objetos son las instancias de las clases, cada que se construye

un objeto de una clase, se está creando una instancia de dicha clase. Por esta razón, se utilizan

indistintamente los términos objeto e instancia de una clase.

Generalmente, las clases se denominan con sustantivos abstractos, como por ejemplo Animal,

Persona, Factura, entre otros.

Ejemplo:

Podemos tener, por ejemplo, una clase denominada Gato con determinadas propiedades y

comportamientos. Una vez creada dicha clase podemos crear dos instancias una llamada

Page 7: OOP Basics

MANUAL DE PROGRAMACION EN C++

133

"Garfield" y otra llamada “Mimi” que tendrán ciertas propiedades específicas y los

comportamientos de dicha clase. Los atributos de la clase Gato podrían ser: sexo, color, raza y

nivel de cansancio. Por su parte, las operaciones de Gato podrían ser: paseo, quieto y muerte.

Algunas de las principales características de las clases son:

Abstracción:

La abstracción de datos permite no preocuparse de los detalles no esenciales. Al tener un conjunto

de objetos con características similares, su comportamiento e información puede abstraerse en

una sola clase abstracta o interfaz para recoger estas semejanzas. La abstracción desde el punto

de vista de la POO expresa las características esenciales de un objeto, las cuales lo diferencian de

los demás, y permiten determinar límites conceptuales entre objetos y entre clases. De esta

manera, la abstracción minimiza la cantidad de características que definen a un objeto y evita

repetición de código.

La abstracción en POO surge del hecho de que cada clase del programa es un modelo de un

"agente" abstracto que puede realizar funciones, informar y cambiar su estado, y "comunicarse"

con otras clases en el sistema sin revelar cómo se implementan estas características. Los procesos,

las funciones o los métodos pueden también ser abstraídos y cuando lo están, una variedad de

técnicas son requeridas para ampliar una abstracción.

Encapsulamiento:

Las clases tienen la propiedad de ocultar información a otras clases. El encapsulamiento hace

referencia a que los atributos de un objeto solo pueden ser modificados por otro objeto a través

de mensajes explícitos enviados por el primero. Es decir, un objeto no puede modificar la

información de otro directamente aunque pueden comunicarse entre sí a través de interfaces.

El encapsulamiento consiste en ocultar los detalles de la implementación de un objeto, a la vez

que se provee una interfaz pública por medio de sus métodos permitidos. También se define como

la propiedad de los objetos de permitir acceso a su estado solamente a través de su interfaz o de

relaciones preestablecidas con otros objetos.

Polimorfismo

Esta propiedad se refiere al hecho de que una misma función puede tener comportamientos

Page 8: OOP Basics

UNIVERSIDAD MILITAR “NUEVA GRANADA” CENTRO DE SISTEMAS

134

diferentes y estar asociada a objetos distintos.

Herencia:

Las clases no están aisladas, sino que se relacionan entre sí, formando una jerarquía de

clasificación. Los objetos heredan las propiedades y el comportamiento de todas las clases a las

que pertenecen. La herencia organiza y facilita el polimorfismo y el encapsulamiento permitiendo

a los objetos ser definidos y creados como tipos especializados de objetos preexistentes. Estos

pueden compartir (y extender) su comportamiento sin tener que re-implementar su

comportamiento. Esto suele hacerse habitualmente agrupando los objetos en clases y estas en

árboles o enrejados que reflejan un comportamiento común. Cuando un objeto hereda de más de

una clase se dice que hay herencia múltiple.

Persistencia

Hace referencia al tiempo que un objeto es mantenido en memoria y puede ser utilizado por

aplicación sin ser destruido. Cuando un objeto deja de ser necesario, éste puede ser destruido y la

memoria que utilizaba puede devolverse al sistema para ser utilizado por la misma u otra

aplicación.

La definición de una clase consta de dos partes: una declaración y una implementación. La

declaración es la lista de los miembros de la clase. La implementación o cuerpo define las

funciones de la clase. A continuación se describen cada uno de estos pasos.

9.2.1 DECLARACIÓN DE UNA CLASE

Las clases están conformadas por un conjunto de características y de funciones, las cuales son

equivalentes a las funciones en los lenguajes estructurados. Se diferencian de ellos en que es

posible acceder a las variables de la clase de forma implícita. A los atributos se les conoce como

miembros dato y son las características que describen el objeto. Las funciones son conocidas en

C++ como funciones miembro o como métodos en otros lenguajes de programación. Dichas

funciones pueden estar relacionadas entre sí, modificar el estado del objeto o invocar

funcionalidades de otros objetos, entre otras cosas.

Una clase se puede definir con struct, union o class pero la forma que caracteriza la POO es utilizar

la palabra reservada class. La sintaxis de una clase es:

Page 9: OOP Basics

MANUAL DE PROGRAMACION EN C++

135

//Sintaxis de la declaración de una clase

class nombre_clase

{

membro_dato1;

miembro_dato2;

...

funcion_miembro1();

funcion_miembro2();

...

};

Como se puede ver 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. Suponga que usted va a desarrollar un programa para manejas el

inventario de su empresa. Para esto definiremos una clase de tipo elemento cuyos miembros

datos podrían ser: nombre, marca y cantidad; sus funciones podrían ser simplemente aumentar

cantidad y disminuir cantidad.

class elemento

{

char nom[20];

char marca[20];

int cantidad;

void aumentar_cantidad(int numero);

void disminuir_cantidad(int numero);

};

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.

En la declaración de una clase se utilizan los especificadores de acceso para controlar la visibilidad de

Page 10: OOP Basics

UNIVERSIDAD MILITAR “NUEVA GRANADA” CENTRO DE SISTEMAS

136

los miembros de una clase, fuera del ámbito de la clase.

Los miembros de una clase pueden ser públicos, privados o protegidos. Las palabras reservadas

public, private y protected se utilizan para controlar el modo de acceso a la clase.

Dentro de una declaración de clase, cada una de estas palabras se puede utilizar para preceder a una

o más declaraciones de los miembros de una clase:

- Acceso público. Los miembros públicos son accesibles por cualquier parte del programa.

- Acceso protegido. Los miembros protegidos significan que sólo se puede acceder a ellos por

“funciones miembro” dentro de la misma clase y por funciones miembro de clases derivadas

de esta clase.

- Acceso privado. Los miembros privados sólo pueden ser utilizados por las “funciones

miembro” de la clase y las funciones amigas de la clase.

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. Considere la clase de tipo artículo que se

declara en el siguiente ejemplo. En ella se tiene dos miembros dato privados y una función

miembro pública.

class articulo

{

private:

float precio;

char nombre[30];

public:

void indicar();

};

Page 11: OOP Basics

MANUAL DE PROGRAMACION EN C++

137

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++.

En el siguiente ejemplo se declara una clase con más miembros que la clase del ejemplo anterior.

Nótese que hay miembros datos cuyo especificador de acceso está sin definir, por lo cual serán

tomados al compilar como miembros dato privados. De igual forma se declara un miembro dato

público. En cuanto a las funciones todas las funciones de la clase son públicas.

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();

};

Miembros dato

La lista de miembros dato de una clase puede comprender cualquier tipo válido en C++. Puede

contener tipos primarios, estructuras e incluso apuntadores a cualquier tipo válido. Los miembros

dato pueden ser incluso clases. En cualquier caso sólo las instancias de clases definidas o

declaradas previamente pueden ser miembros.

Page 12: OOP Basics

UNIVERSIDAD MILITAR “NUEVA GRANADA” CENTRO DE SISTEMAS

138

Los miembros dato declarados en la clase se deben considerar equivalentes a campos de una

estructura, no a variables. Tal como las estructuras, se debe declarar un objeto de un tipo clase y a

continuación se inicializan sus miembros dato.

Además de los especificadores de acceso utilizados para definir los miembros de una clase. Un

miembro dato de una clase se puede declarar estático (static). Para un miembro dato, la

designación static significa que existe sólo una instancia de ese miembro. Un miembro dato

estático es compartido por todos los objetos de una clase. A un miembro dato static se le asigna

una zona fija de almacenamiento en tiempo de compilación, al igual que una variable global, pero

el identificador de la variable está dentro de ámbito utilizando solamente el operador (::) con el

nombre de la clase.

Los miembros datos se asignan generalmente con la misma clase de almacenamiento. Para

declarar o inicializar un miembro static se utiliza la misma notación que una variable global.

class ejemplo

{

public:

static int valor; //declarar miembro estático

};

int ejemplo::valor; //definir miembro estático

void main()

{

ejemplo e1,e2;

e1.valor=1;

e2.valor=10;

}

A los miembros dato static se puede acceder:

Page 13: OOP Basics

MANUAL DE PROGRAMACION EN C++

139

- Utilizando el operador punto

- Utilizando el operador flecha, si el lado izquierdo es un apuntador a objeto

- Utilizando el identificador de la clase sin referenciar un objeto real: ejemplo::valor=3;

Los miembros datos static no siempre tienen que ser public.

class ejemplo

{

private:

static int valor; //declarar miembro estático

};

int ejemplo::valor=5; //definir miembro estático

void main()

{

ejemplo e1;

e1.valor=1; //error: acceso no válido

}

Para acceder a un miembro dato private static se necesita utilizar el operador (::). Otros medios

son:

- A través de una función miembro de la clase

- A través de una función declarada amiga de la clase

Funciones miembro

Una operación de una clase, es un servicio que la clase proporciona a los clientes de la clase. Por lo

general, los objetos no realizan sus operaciones de manera autónoma sino que requieren de la

recepción de un mensaje que es enviado por un objeto cliente.

Page 14: OOP Basics

UNIVERSIDAD MILITAR “NUEVA GRANADA” CENTRO DE SISTEMAS

140

Las funciones miembro implementan las operaciones permitidas sobre los tipos de datos de una

clase. Para declarar una función miembro hay que situar su prototipo en el cuerpo de la clase. No

hay que definir la función dentro de la clase; dicha definición puede estar fuera de la clase e

incluso en un archivo independiente, aunque también pueden ser definidas en línea dentro de la

clase.

Las funciones miembro son necesarias para acceder a los datos privados. En general, son públicas;

si no lo fueran, ninguna otra función podría llamarlas. Se pueden declarar para devolver valores

con tipos incluyendo objetos de clases, apuntadores o referencias. Pueden ser declaradas también

para aceptar cualquier número y tipo de argumentos. Los argumentos por defecto están

permitidos, así como la notación de puntos suspensivos.

9.2.2 IMPLEMENTACIÓN DE UNA CLASE

Una vez se ha declarado la clase es necesario definir cada una de las funciones miembro que ésta

contiene. 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. Una de las principales

características de las funciones miembro es que éstas por pertenecer a la clase pueden tener

acceso a las componentes privadas de la clase.

Existen dos opciones para llevar a cabo la implementación de las funciones miembro de las clases.

- En la primera opción la función de define en línea (inline). Por cada llamada a esta función,

el compilador genera (vuelve a copiar) las diferentes instrucciones de la función, por

consiguiente, no existe una única copia de la función dentro del código sino que cada vez

que se realiza una llamada a la función se crea una copia de ella en lugar de invocarla. La

ventaja de este tipo de funciones es que el programa se ejecuta más rápidamente, el

inconveniente es que se requiere mayor espacio en memoria para su ejecución.

Hay dos formas de implementar la declaración en línea. La primera es implementando la

función inmediatamente ésta es declarada y la segunda es haciendo uso de la palabra

reservada inline. En esta última se utiliza el operador de resolución de ámbito (::) para

identificar la clase a la cual pertenece la función

En la siguiente tabla se presenta un ejemplo de las dos formas de implementaciones de

Page 15: OOP Basics

MANUAL DE PROGRAMACION EN C++

141

funciones en línea. En la primera celda implementando la función dentro de la declaración

y en la segunda utilizando la palabra reservada inline.

class ejemplo

{

int x,y;

public:

void f()

{

cout<<"x= "<<x<<" y= "<<y<<endl;

}

};

class ejemplo

{

int x,y;

public:

void f();

};

inline void ejemplo::f()

{

cout<<"x= "<<x<<" y= "<<y<<endl;

}

- En la segunda opción la función f se llamará con una llamada verdadera de función. En

este caso la función se implanta por fuera de la declaración de la clase. En este caso

también se hace uso del operador de resolución de ámbito (::) para identificar la clase a la

cual pertenece la función. En el siguiente ejemplo se presenta la misma clase llamada

ejemplo del ejemplo anterior pero ahora la función f está implementada fuera de la

declaración.

//Declaración de una clase y definición de función miembro fuera de la clase

class ejemplo

{

int x,y;

public:

void f();

};

void ejemplo::f()

{

cout<<"x= "<<x<<" y= "<<y<<endl;

Page 16: OOP Basics

UNIVERSIDAD MILITAR “NUEVA GRANADA” CENTRO DE SISTEMAS

142

}

Esta declaración 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.

9.3 OBJETOS

Un objeto es un elemento declarado de un tipo clase. Se conoce también como una instancia de

una clase. Los objetos se pueden tratar como cualquier variable C++. La principal diferencia es que

se puede llamar a cualquiera de las funciones que pertenecen a un objeto, esto es, se puede

enviar un mensaje a ella.

La comunicación con el objeto se realiza a través del paso de mensajes. El envío a una instancia de

una clase produce la ejecución de una función miembro. El paso de mensajes es el término

utilizado para referirnos a la invocación o llamada de una función miembro de un objeto.

Retomando el primer ejemplo de la sección 2.2.1 en donde se tenía la declaración de una clase de

tipo elemento para manejar un inventario un objeto de esta clase se definiría como todas las

variables en C++, de la siguiente manera:

elemento tornillos, tuercas;

De igual forma, haciendo uso del tercer ejemplo de la sección 2.2.1, se definió una clase de tipo

alfa. Una vez definida esta clase, ésta puede ser usada dentro del main() como se presenta en el

siguiente ejemplo. Nótese que en primer lugar se define un objeto del tipo alfa. Posteriormente se

hace uso de las funciones miembros, las cuales se definieron como públicas y no se produce

ningún error. Sin embargo, no se puede acceder a los miembros privados.

int main()

{

alfa obj; //declaración de un objeto

Page 17: OOP Basics

MANUAL DE PROGRAMACION EN C++

143

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

return 0;

}

9.3.1 ASIGNACIÓN DINÁMICA DE MEMORIA

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

cadena cad1("hola");

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();

Page 18: OOP Basics

UNIVERSIDAD MILITAR “NUEVA GRANADA” CENTRO DE SISTEMAS

144

};

cadena::cadena(int lon)

{

datos=new char[lon];

}

cadena::~cadena()

{

delete datos;

}

9.3.2 CONSTRUCTORES

El objetivo de un constructor es el de inicializar un objeto cuando éste es creado. Asignaremos los

valores iniciales así como los procesos que ésta clase deba realizar.

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

Page 19: OOP Basics

MANUAL DE PROGRAMACION EN C++

145

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.

Ejemplo

class prueba

{

tipo1 d1;

tipo2 d2;

tipo3 d3;

public:

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 copia. 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:

Page 20: OOP Basics

UNIVERSIDAD MILITAR “NUEVA GRANADA” CENTRO DE SISTEMAS

146

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 correcto 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 elemento dato equivalente del objeto de la

derecha del operador =.

9.3.3 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.

Considere el siguiente ejemplo en el cual se crea la clase cadena con su constructor y destructor

correspondiente.

class cadena {

public:

cadena(); // Constructor por defecto

~cadena(); // Destructor

void Asignar(char *dest);

char *Leer(char *c);

private:

Page 21: OOP Basics

MANUAL DE PROGRAMACION EN C++

147

char *cad; // Puntero a char: cadena de caracteres

};

cadena::cadena() : cad(NULL) {}

cadena::~cadena() {

delete[] cad; // Libera la memoria reservada a cad

}

void cadena::Asignar(char *dest) {

// Eliminamos la cadena actual:

delete[] cad;

// Reservamos memoria para la nueva y la almacenamos

cad = new char[strlen(dest)+1];

// Reserva memoria para la cadena

strcpy(cad, dest); // Almacena la cadena

}

char *cadena::Leer(char *c) {

strcpy(c, cad);

return c;

}

9.3.4 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. Esto se conoce

como sobrecarga de funciones o sobrecarga de operadores. Estas funciones y operadores se dicen

que están sobrecargados y se pueden utilizar para redefinir una función u operador definido.

Sobrecarga de funciones

Page 22: OOP Basics

UNIVERSIDAD MILITAR “NUEVA GRANADA” CENTRO DE SISTEMAS

148

Dos funciones pueden tener el mismo nombre pero tener una implementación y argumentos de

entrada y variables de retorno diferentes. Esta característica se conoce como sobrecarga de

funciones. Por consiguiente, cuando se habla de una función sobrecargada se hace referencia a

una función que tiene más de una definición.

Las funciones sobrecargadas suelen diferenciarse por el número y tipo de argumentos, aunque

también hay funciones sobrecargadas que devuelven tipos distintos.

En la programación orientada a objetos las funciones sobrecargadas suelen utilizarse para las

funciones miembro y constructora de la 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.

Considere el mismo ejemplo del numeral anterior. Ahora vamos a sobrecargar la función

constructora de la clase cadena.

class cadena {

public:

cadena(); // Constructor por defecto

cadena(char *c); // Constructor desde cadena c

cadena(int n); // Constructor de cadena de n caracteres

cadena(const cadena &); // Constructor copia

~cadena(); // Destructor

void Asignar(char *dest);

char *Leer(char *c);

private:

char *cad; // Puntero a char: cadena de caracteres

};

cadena::cadena() : cad(NULL) {}

cadena::cadena(char *c) {

Page 23: OOP Basics

MANUAL DE PROGRAMACION EN C++

149

cad = new char[strlen(c)+1];// Reserva memoria para cadena

strcpy(cad, c); // Almacena la cadena

}

cadena::cadena(int n) {

cad = new char[n+1]; // Reserva memoria para n caracteres

cad[0] = 0; // Cadena vacía

}

cadena::cadena(const cadena &Cad) {

// Reservamos memoria para la nueva y la almacenamos

cad = new char[strlen(Cad.cad)+1];

// Reserva memoria para cadena

strcpy(cad, Cad.cad); // Almacena la cadena

}

cadena::~cadena() {

delete[] cad; // Libera la memoria reservada a cad

}

void cadena::Asignar(char *dest) {

// Eliminamos la cadena actual:

delete[] cad;

// Reservamos memoria para la nueva y la almacenamos

cad = new char[strlen(dest)+1];

// Reserva memoria para la cadena

strcpy(cad, dest); // Almacena la cadena

}

Page 24: OOP Basics

UNIVERSIDAD MILITAR “NUEVA GRANADA” CENTRO DE SISTEMAS

150

char *cadena::Leer(char *c) {

strcpy(c, cad);

return c;

}

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) {...} , en donde 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.

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

Page 25: OOP Basics

MANUAL DE PROGRAMACION EN C++

151

función es operator op, donde op es el operador que se sobrecarga.

9.4 FUNCIONES AMIGA

Una función amiga es una función no miembro de una clase que puede tener acceso a las partes

privadas de una clase; se debe declarar como amiga de la clase mediante la palabra reservada

friend.

Las funciones amigas se declaran situando su prototipo de función en la clase de la que son amiga

precediéndola con la palabra reservada friend. Por ejemplo:

class cosa

{

int datos;

public:

friend void cargar (cosa& t, int x);

};

void cargar(cosa& t, int x)

{

t.datos=x;

}

Como la función cargar se declara amiga de la clase cosa puede acceder al miembro privado datos.

Las razones fundamentales para utilizar funciones amigas es que algunas funciones necesitan

acceso privilegiado a más de una clase. Una segunda razón es que las funciones amigas pasan

todos sus argumentos a través de la lista de argumentos y cada valor de argumento se somete a la

conversión de asignación.

Por último, consideremos el siguiente ejemplo en el cual se hace uso de las funciones amiga. Se

puede ver que la clase miclase tiene una función amiga llamada factor que tiene acceso inmediato

Page 26: OOP Basics

UNIVERSIDAD MILITAR “NUEVA GRANADA” CENTRO DE SISTEMAS

152

a los datos miembro privados de la clase n y d. Ahí radica la importancia de definiciones de las

funciones amiga.

#include <iostream>

using namespace std;

class miclase{

int n,d;

public:

miclase(int i, int j){n=i;d=j;}

friend int factor(miclase ob);

};

int factor(miclase ob)

{

if (!(ob.n%ob.d))

return 1;

else

return 0;

}

void main()

{

miclase obj1(10,2), obj2(3,2);

if(factor(obj1))

cout << "es factor";

else

cout << "no es factor";

}

9.4.1 CLASES AMIGAS

No sólo puede ser una función, amiga de una clase, también una clase completa puede ser amiga

de otra clase. En este caso todas las funciones de la clase amiga pueden acceder a las partes

privadas de la otra clase.

Page 27: OOP Basics

MANUAL DE PROGRAMACION EN C++

153

Una clase amiga puede ser declarada antes de que pueda ser designada como amiga.

class animales;

class hombre

{

public:

friend class animales;

};

class animales

{//..

};

Cada función miembro de animales es amiga de la clase hombre. La designación de un amigo

puede estar en una sección private o public de una clase.

Resumen

Las clases permiten al programador modelar objetos con atributos y comportamientos. Se puede

utilizar el nombre de una clase como el nombre de un tipo de dato para declarar instancias de

dicha clase conocidas como objetos.

Las definiciones de la clase empiezan con la palabra reservada class. El cuerpo de la definición se

encuentro delimitado a través de llaves ({}).

Cualquier dato o función miembro de tipo public puede ser accedida y utilizada por otras clases.

Las funciones o datos de tipo private solo son accesibles a clases amigas o miembros de la misma

clase.

Los especificadores de acceso a miembros terminan con dos puntos (:).

Un constructor es una función miembro especial con el mismo nombre de la clase que se encarga

de crearla.

Page 28: OOP Basics

UNIVERSIDAD MILITAR “NUEVA GRANADA” CENTRO DE SISTEMAS

154

Actividades complementarias

1. Crear una clase llamada empleado que contenga como dato miembro el nombre y el

número de empleado, y como funciones miembro Leerdatos() y Verdatos() que lean los

datos del teclado y los visualice en pantalla, respectivamente.

2. Cree una clase llamada complejo para realizar aritmética con números complejos. Los

números complejos tienen la forma: iba , en donde a es la parte real y b es la parte

imaginaria.

Utilice variables double para representar los datos de tipo private de la clase, es decir la

parte real e imaginaria. Cree un constructor que permita inicializar un objeto de esta clase

cuando se declare. Proporcione funciones miembro de tipo public para realizar lo

siguiente:

o Suma de dos números complejos: las partes reales se suman juntas y las partes

imaginarias se suman juntas.

o Resta de dos números complejos: la parte real del operando derecho se resta a la

parte real del operando izquierdo y la parte imaginaria del operando derecho se

resta a la parte imaginaria del operando izquierdo.

o Impresión de números complejos de la forma (a , b) en donde a es la parte real y

b es la parte imaginaria.

Lecturas recomendadas

SMITH JO ANN, C++ Programación Orientada a Objetos. Editorial Paraninfo, 1999. Páginas 5 a 45.

JOYANES, Luis J., Programación en C++, Algoritmos, estructuras de datos y objetos. Editorial Mc

Graw Hill, 2ª Edición 2002. Páginas 265 a 277 y 457 a 477.