Está en la página 1de 12

Universidad de Oriente

Asignatura: Diseño y Programación Orientada a Objetos.

Clase: 2

Título: Instanciación de objetos mediante constructores.

Introducción
En la clase anterior, aprendimos un nuevo recurso del lenguaje, las clases. Este recurso de primordial
importancia, nos permite representar objetos del mundo real en función de sus características (atributos)
y comportamientos (métodos o funciones). Al implementar una clase, se crea un nuevo tipo de dato
definido por el usuario, con el nombre de la clase, permitiendo declarar variables o usando la terminología
correcta, instanciar objetos de esta en nuestros programas. En esta clase, aprenderemos a crear objetos
con todos sus valores al momento de la instanciación, mediante constructores, garantizando así que los
métodos de un objeto solo puedan ser invocados, después de que el objeto esté en un estado consistente.
Aprenderemos también a usar colecciones de objetos y a instanciar un objeto a partir de apuntadores.

Constructor
Recordemos la declaración de la clase cuenta.

Cuando usamos la instrucción:

Cuenta miCuenta;

Estamos instanciando un objeto de tipo Cuenta. En este caso, los atributos de miCuenta son inicializados
con su valor por defecto, en el caso de del atributo nombre, el valor por defecto del tipo de datos string,
es la cadena vacía; pero en el caso del atributo saldo, el tipo de dato float no tiene un valor por defecto
por lo que se inicializa con un valor basura, como se puede apreciar en el siguiente ejemplo.

¿Qué pasa si usted desea proporcionar el nombre y el saldo de una cuenta a la hora de crear un objeto
Cuenta? Cada clase que usted declare puede proporcionar un constructor, el cual puede utilizarse para
inicializar un objeto de una clase al momento de crear ese objeto. Un constructor es una función miembro
especial que debe definirse con el mismo nombre que el de la clase, de manera que el compilador pueda
diferenciarlo de las demás funciones miembro de la clase. Una importante diferencia entre los
constructores y las otras funciones es que los primeros no pueden devolver valores, por lo cual no
pueden especificar un tipo de valor de retorno (ni siquiera void). Por lo general, los constructores se
declaran como public.

C++ requiere una llamada al constructor para cada objeto que se crea, lo cual ayuda a asegurar que cada
objeto se inicialice antes de utilizarlo en un programa. La llamada al constructor ocurre de manera
implícita cuando se crea el objeto. Si una clase no incluye un constructor en forma explícita, el
compilador proporciona un constructor por defecto, es decir, un constructor sin parámetros. Por
ejemplo, cuando en la línea 9 del ejemplo anterior se crea un objeto Cuenta, se hace una llamada al
constructor por defecto. Este constructor proporcionado por el compilador crea un objeto Cuenta sin
proporcionar ningún valor inicial para los atributos del objeto. [Nota: para los miembros de datos que son
objetos de otras clases, el constructor llama de manera implícita al constructor predeterminado de cada
miembro de datos, para asegurar que ese miembro de datos se inicialice en forma apropiada. Ésta es la
razón por la cual el miembro de datos string llamado nombre se inicializó con la cadena vacía; el
constructor por defecto para la clase string asigna al valor del objeto la cadena vacía. Más adelante en el
curso aprenderemos más acera de cómo inicializar miembros de datos que sean objetos de otras clases.]

En el siguiente ejemplo, especificamos el nombre y el saldo de un objeto Cuenta cuando se crea (línea 10,
main.cpp). En este caso, los argumentos “Carmen de Mairena” y 100 se pasan al constructor del objeto
Cuenta (línea 12 en Cuenta.h y líneas 5 a 13 en Cuenta.cpp) y se utiliza para inicializar el nombreCurso y
el saldo. En el siguiente programa se define una clase una clase Cuenta modificada, la cual contiene un
constructor con un parámetro string que recibe el nombre inicial de la cuenta y un parámetro float que
recibe el saldo inicial.
Definición de un constructor
En la línea 12 de Cuenta.h se declara un constructor para la clase Cuenta. Observe que el constructor tiene
el mismo nombre que su clase, Cuenta. Un constructor especifica en su lista de parámetros los datos que
requiere para realizar su tarea. Al crear un nuevo objeto, el programador coloca estos datos en los
paréntesis que van después del nombre del objeto (como hicimos en las líneas 10 y 11 del fichero
main.cpp). En la línea 12 del fichero cabecera (Cuenta.h) se indica que el constructor de la clase Cuenta
tiene un parámetro string llamado nombre y un parámetro float llamado saldo. Observe que en la línea
12 no se especifica un tipo de valor de retorno, ya que los constructores no pueden devolver valores (ni
siquiera void).

En las líneas 11 y 12, en el cuerpo del constructor (Cuenta.cpp) se pasa el parámetro nombre a la función
miembro setNombre, la cual asigna un valor al miembro de datos (atributo) nombre y se pasa el
parámetro saldo a la función setSaldo, la cual asigna un valor al miembro de datos saldo.

Prueba de la clase Cuenta


En las líneas 7 a 22 del fichero main.cpp se define la función main que prueba la clase Cuenta y demuestra
cómo inicializar objetos Cuenta mediante el uso de un constructor. En la línea 10, en la función main se
crea y se inicializa un objeto Cuenta llamado carmen. Cuando se ejecuta esta línea, C++ hace una llamada
implícita al constructor de Cuenta con los argumentos "Carmen de Mairena" y 100 para inicializar
el nombre y el saldo de la cuenta carmen. En la línea 11 se repite este proceso para el objeto Cuenta
llamado mara, pero esta vez se pasan los argumentos "Mara Salvatrucha" y 80000000 para inicializar
el nombre y el saldo de mara. En las líneas 13 y 19 se utiliza la función miembro getNombre de cada
objeto para obtener los nombres de las cuentas y mostrar que, sin duda, se inicializaron al momento de
crear los objetos. La salida confirma que cada objeto Cuenta mantiene su propia copia del miembro de
datos nombre.

Dos formas de proporcionar un constructor por defecto para una clase.


Cualquier constructor que no recibe argumentos se llama constructor por defecto. Una clase puede recibir
un constructor por defecto en una de dos formas:

1. El compilador crea de manera implícita un constructor por defecto en una clase que no define a
un constructor. Dicho constructor por defecto no inicializa los miembros de datos de la clase, pero
llama al constructor por defecto para cada miembro de datos que sea un objeto de otra clase.
[Nota: por lo general, una variable sin inicializar contiene un valor “basura” (por ejemplo, una
variable int sin inicializar podría contener -858993460, que probablemente sea un valor
incorrecto para esa variable en la mayoría de los programas)].
2. El programador define de forma explícita un constructor que no recibe argumentos. Dicho
constructor por defecto realizará la inicialización especificada por el programador, y llamará al
constructor por defecto para cada miembro de datos que sea un objeto de otra clase.
Si define un constructor sin argumentos, C++ no creará de manera implícita un constructor por defecto
para esa clase.

Un constructor que utiliza valores predeterminados para todos sus argumentos también es un constructor
por defecto; es decir, un constructor que se puede invocar sin argumentos. Puede haber solo un
constructor por defecto por clase.

A menos que no sea necesario inicializar los miembros de datos de su clase (casi nunca), debe
proporcionar un constructor para asegurar que los miembros de datos de su clase se inicialicen con
valores significativos al momento de crear cada nuevo objeto de su clase.

Los miembros de datos se pueden inicializar en un constructor de la clase, o sus valores pueden
establecerse más adelante, después de crear el objeto. Sin embargo, es una buena práctica de ingeniería
de software asegurarse que un objeto esté inicializado por completo antes de que el código cliente
invoque las funciones miembro de ese objeto. En general, no debemos depender del código cliente para
asegurar que un objeto se inicialice de manera apropiada.

Crear objetos a través de apuntadores.


Los apuntadores en C++ son un recurso muy importante y muy usado. Por lo que también es posible,
instanciar objetos a través de apuntadores. Ya aprendimos que los objetos se crean con una llamada a un
constructor de la clase; para llamar a un constructo a través de un apuntador se utiliza el operador new.
Vamos a modificar la función main del programa anterior para crear los objetos, en este caso con
apuntadores.

En las líneas 11 y 12 se crean dos punteros a Cuenta, *carmen y *mara. El operador new seguido de
una llamada a un constructor de la clase, instancia un objeto tipo Cuenta y retorna la dirección de
memoria donde este está ubicado, la cual es asignada al apuntador. En las líneas 14, 19, 20 y 21 se llaman
a los métodos getNombre y getSaldo de los objetos apuntados por *mara y *carmen; para invocar
funciones o acceder a los atributos de un objeto a través de un puntero, se utiliza el operador selección
de miembro mediante apuntador (->) a diferencia del operador de selección de miembro mediante
objeto (.).

Colecciones de objetos.
Hasta el momento, en los programas que hemos desarrollado, solo se han instanciado uno o dos objetos,
en esta sección veremos cómo almacenar una cantidad arbitraria de objetos para su procesamiento.
Existen varias colecciones en la librería estándar de C++, que sirven para almacenar objetos, pero aquí
utilizaremos arreglos para demostrar como almacenar un conjunto de objetos.

Mediante arreglos, podemos almacenar los objetos de dos maneras, podemos utilizar un arreglo de
objetos, o un arreglo de a punteros a objetos. Veamos el siguiente enunciado:

Se tienen los datos de una cantidad determinada de cuentas. De las cuentas se conoce el número de
cuenta, el nombre del dueño de la cuenta y el saldo de la cuenta. Lea los datos de las n cuentas por teclado
y muestre toda la información de la cuenta con mayor saldo.
En las líneas 24 a 26 del fichero Cuenta.cpp se declaran los atributos de la clase, nombre, número y saldo.
En la línea 12 se declara el constructor de la clase que inicializa los atributos de la clase. Al tener la clase
un constructor explícito, el compilador no provee un compilador por defecto.

En la línea 55 del fichero main.cpp se declara el arreglo de punteros donde se van almacenar las cuentas.

Cuenta **cuentas;

La variable cuentas es un puntero a puntero a Cuenta, lo hacemos de esta manera para que el arreglo sea
dinámico. En las líneas 58 y 59 se pide al usuario y se lee por teclado, la cantidad de cuentas y se almacena
en la variable n. En la línea 62 se reserva memoria para almacenar n punteros a Cuenta.

cuentas = new Cuenta*[n];

En el ciclo de la línea 64 se leen las cuentas por teclado, mediante la función leerCuenta, que recibe un
puntero a Cuenta por referencia ya que se va a modificar su valor, o sea se le va a asignar la nueva cuenta
que se cree.

En la línea 24, dentro del cuerpo de la función leerCuenta, luego de leer los 3 atributos de la nueva cuenta
se llama al constructor de la clase y se le asigna la dirección del objeto creado al puntero que recibe la
función por referencia.

cuenta = new Cuenta(numero, nombre, saldo);

En las líneas 38 a 51 se define la función cuentaMayorSaldo, que recibe un arreglo de punteros a


Cuenta, y el tamaño de dicho arreglo; y retorna la posición de la cuenta con mayor saldo. Noten que, para
acceder a los métodos de la clase a través de un puntero, se utiliza el operador selección de miembro
mediante apuntador (->) a diferencia del operador de selección de miembro mediante objeto (.).

Arreglo de objetos en vez de arreglo de punteros.


Se preguntarán por qué no utilizar un arreglo de objetos en vez de un arreglo de punteros. Veremos a
continuación como crear un arreglo de objetos y sus desventajas.

Para tener un arreglo dinámico es obligatorio hacerlo mediante punteros por lo que la declaración y
creación sería de la manera siguiente, asumiendo que ya está inicializada la variable n con la cantidad de
objetos que se desean crear:

Cuenta *cuentas;
cuentas = new Cuenta[n];

Cuando se ejecuta esta última línea el compilador intenta invocar de manera implícita el constructor por
defecto de la clase, para cada objeto del arreglo. Si la clase no dispone de un constructor por defecto, ya
sea implícito o explícito, se produce un error de compilación.
Por este motivo, y como habíamos visto que a no ser que sea muy necesario el constructor por defecto,
casi nunca; la forma preferida para almacenar un conjunto de objetos es a través de un arreglo de
punteros.

Conclusiones
Aprendimos que es un constructor de una clase, que es el encargado de instanciar objetos de una clase.
Si no se define un constructor, el compilador brinda un constructor por defecto, dicho constructor no
inicializa los atributos primitivos de la clase. Un constructor por defecto es un constructor que no recibe
parámetros. Los constructores tienen exactamente el mismo nombre de la clase y no retornan nada, ni
siquiera void. Vimos también como almacenar un conjunto de objetos, lo cual podía se mediante un
arreglo de objetos o un arreglo de punteros a objetos, dónde la forma preferida era utilizar un arreglo de
punteros a objetos ya que, si usáramos un arreglo de objetos, estaríamos obligados a instanciar los objetos
mediante el constructor

También podría gustarte