Utilizando objetos en C++ - Pájaros
Hasta ahora hemos estudiado cómo utilizar variables para guardar y manipular datos de cierto tipo y cómo estructurar nuestros programas dividiendo las tareas en funciones. Un objeto es una entidad que se utiliza en muchos lenguajes de programación para encapsular los datos y el código que opera en ellos. En la experiencia de laboratorio de hoy, utilizarás una clase llamada Bird
para practicar algunas de las destrezas básicas en C++ para la creación y manejo de objetos.
Objetivos:
- Crear objetos de una clase.
- Analizar la declaración de una clase para entender cómo crear y manipular objetos de esa clase.
- Practicar la creación y manipulación de objetos, y la invocación de "setters" y "getters".
Pre-Lab:
Antes de llegar al laboratorio debes haber:
Repasado los siguientes conceptos:
a. La creación de objetos de una clase.
b. La utilización de métodos "getters" para acceder a los atributos de un objeto.
c. La utilización de métodos "setters" para modificar los atributos de un objeto.
Estudiado la documentación de la clase
Bird
disponible abriendo el archivo/home/eip/labs/objects-birds/doc/es/html/class_bird.html
(usando el navegador) en la máquina virtual.Estudiado los conceptos e instrucciones para la sesión de laboratorio.
Tomado el quiz Pre-Lab, disponible en Moodle.
Clases y objetos en C++
Un objeto es un ente que contiene datos y procedimientos para manipularlos. Al igual que cada variable tiene un tipo de dato asociada a ella, cada objeto tiene una clase asociada que describe las propiedades de los objetos: sus datos (atributos), y los procedimientos con los que se pueden manipular los datos (métodos).
Para utilizar objetos de una clase no es necesario entender todos los detalles de su implementación. Basta entender cómo crearlos e interactuar con ellos. La información necesaria está disponible en la documentación de la clase. Antes de crear objetos de cualquier clase debemos familiarizarnos con su documentación. La documentación nos indica, entre otras cosas, qué ente se está tratando de representar con la clase, y cuáles son los interfaces o métodos disponibles para manipular los objetos de la clase.
Dale un vistazo a la documentación de la clase Bird
que se encuentra en el archivo /home/eip/labs/objects-birds/doc/es/html/class_bird.html
(en la máquina virtual)
Clases
Una clase es una descripción de los miembros dato y las funciones miembro de un objeto. La declaración de una clase establece los atributos (miembros dato) que tendrá cada objeto de esa clase y los métodos (funciones miembro) que pueden invocar.
Si no se especifica lo contrario, los miembros dato y funciones miembro definidos en una clase son privados. Esto quiere decir que esos miembros solo se pueden acceder y cambiar mediante funciones miembro públicas de la clase (constructores, "setters" y "getters", entre otros).
Lo siguiente es el esqueleto de la declaración de una clase:
class NombreClase
{
// Declaraciones
private:
// Declaraciones de miembros dato y
// prototipos de funciones miembro
// que sean privados para esta clase
tipo miembroDatoPrivado;
tipo funcionMiembroPrivada(tipo de los parámetros);
public:
// Declaraciones de miembros dato y
// prototipooks de funciones miembro
// que sean públicos para todo el programa
tipo miembroDatoPublico;
tipo funcionMiembroPublica(tipo de los parámetros);
};
Puedes ver la declaración de la clase Bird
en el archivo bird.h
incluido en el programa de esta experiencia de laboratorio.
Objetos
Un objeto es un ente que contiene datos llamados sus atributos o miembros dato, y también contiene procedimientos, llamados métodos o funciones miembro, que se usan para manipularlos. Los objetos son instancias de una clase que se crean de manera similar a como se definen las variables. Por ejemplo, ya conoces como crear objetos de tipo string
en tus programas:
string nombre;
Una vez creamos un objeto, podemos interactuar con él usando los métodos de la clase a la que pertenece.
Métodos de una clase
Los métodos o funciones miembro de una clase determinan qué acciones podemos tomar sobre los objetos de esa clase. Los métodos son parecidos a las funciones en el sentido de que pueden recibir parámetros y regresar un resultado. Una forma elemental de conocer los métodos de una clase es leyendo la declaración de la clase. Por ejemplo, el siguiente código es parte de la declaración de la clase Bird
en el archivo bird.h
.
class Bird : public QWidget {
private:
int size;
QString faceColor;
.
.
public:
Bird(int , EyeBrowType , QString , QString, QWidget *parent = 0) ;
int getSize() const;
EyeBrowType getEyebrow() const ;
QString getFaceColor() const;
QString getEyeColor() const;
Qt::GlobalColor getColor(QString) const;
void setSize(int) ;
void setEyebrow(EyeBrowType) ;
void setFaceColor(QString) ;
void setEyeColor(QString) ;
.
.
};
Una vez creado un objeto, sus métodos proveen la única forma de cambiar sus atributos, obtener información o hacer cómputos en los mismos. Es por esto que comúnmente se llama interfaz al conjunto de métodos de una clase. Los métodos son la interfaz entre el usuario de un objeto y su contenido.
Digamos que en tu programa defines un objeto llamado Piolin
de clase Bird
así:
Bird Piolin;
Para acceder y/o modificar los valores de los miembros de dato de Piolin
debes hacerlo usando la función miembro adecuada. Por ejemplo, si quisieras cambiar el valor al miembro dato size
de Piolin
lo harías llamando a la función miembro setSize
así:
Piolin.setSize(100)
Constructores
Los primeros métodos de una clase que debemos entender son los constructores. Una clase puede tener múltiples constructores. Uno de los constructores será invocado automáticamente cada vez que se crea un objeto de esa clase. En la mayoría de los casos, los constructores se utilizan para inicializar los valores de los atributos del objeto. Para poder crear objetos de una clase, debemos conocer cuáles son sus constructores.
En C++, los constructores tienen el mismo nombre que la clase y no tienen tipo de valor de regreso (ya que no devuelven ningún valor). La clase Bird
que estarás usando en la sesión de hoy tiene dos constructores (funciones sobrecargadas):
Bird (QWidget *parent=0)
Bird (int, EyeBrowType, QString, QString, QWidget *parent=0)
Puedes ver las declaraciones de los prototipos de estos métodos en la declaración de la clase Bird
en el archivo bird.h
del proyecto o en la documentación (/home/eip/labs/objects-birds/doc/es/html/class_bird.html
). El primer constructor, Bird (QWidget *parent=0)
, es un método que se puede invocar con uno o ningún argumento. Si al invocarlo no se usa argumento, el parámetro de la función toma el valor 0.
El constructor de una clase que se puede invocar sin usar argumentos es el constructor por defecto ("default") de la clase; esto es, el constructor que se invoca cuando creamos un objeto usando una instrucción como:
Bird pitirre;
Puedes ver las implementaciones de los métodos de la clase Bird en el archivo bird.cpp
. Nota que el primer constructor, Bird (QWidget *parent=0)
, asignará valores aleatorios ("random") a cada uno de los atributos del objeto. Más adelante hay una breve explicación de la función randInt
.
Dale un vistazo a la documentación del segundo constructor, Bird (int, EyeBrowType, QString, QString, QWidget *parent=0)
. Esta función requiere cuatro argumentos y tiene un quinto argumento que es opcional porque tiene un valor predeterminado. Una manera para usar este constructor es creando un objeto como el siguiente:
Bird guaraguao(200, Bird::UPSET, "blue", "red");
"Setters" ("mutators")
Las clases proveen métodos para modificar los valores de los atributos de un objeto que se ha creado. Estos métodos se llaman "setters" o "mutators". Usualmente se declara un "setter" por cada atributo que tiene la clase. La clase Bird
tiene los siguientes "setters":
void setSize (int)
void setEyebrow (EyeBrowType)
void setFaceColor (QString)
void setEyeColor (QString)
El código en el siguiente ejemplo crea el objeto bobo
de la clase Bird
y luego cambia su tamaño a 333.
Bird bobo;
bobo.setSize(333);
"Getters" ("accessors")
Las clases también proveen métodos para acceder ("get") el valor del atributo de un objeto. Estos métodos se llaman "getters" o "accessors". Usualmente se declara un "getter" por cada atributo que tiene la clase. La clase Bird
tiene los siguientes "getters":
int getSize ()
EyeBrowType getEyebrow ()
QString getFaceColor ()
QString getEyeColor ()
El código en el siguiente ejemplo crea el objeto piolin
de la clase Bird
e imprime su tamaño.
Bird piolin;
cout << piolin.getSize();
Otras funciones o métodos que utilizarás en esta experiencia de laboratorio
MainWindow: El archivo mainwindow.h
contiene la declaración de una clase llamada MainWindow
. Los objetos que sean instancias de esta clase podrán utilizar los métodos sobrecargados
void MainWindow::addBird(int x, int y, Bird &b)
void MainWindow::addBird(Bird &b)
que añadirán a la pantalla un dibujo del objeto de la clase Bird
que es recibido como argumento. El código en el siguiente ejemplo crea un objeto w
de la clase MainWindow
, crea un objeto zumbador
de la clase Bird
y lo añade a la posición (200, 200) de la pantalla w
.
MainWindow w;
Bird zumbador;
w.addBird(200, 200, zumbador);
Figura 1. Ventana w
con la imagen del objeto zumbador
en la posición (200, 200).
¡Importante! No es suficiente solo crear los objetos Bird
para que éstos aparezcan en la pantalla. Es necesario usar uno de los métodos addBird
para que el dibujo aparezca en la pantalla.
randInt: La clase Bird
incluye el método
int Bird::randInt(int min, int max)
para generar números enteros aleatorios ("random") en el rango [min, max]. El método randInt
depende de otra función para generar números aleatorios que requiere un primer elemento o semilla para ser evaluada. En este proyecto, ese primer elemento se genera con la invocación srand(time(NULL)) ;
.
Bird
?
setEyeColor
setFaceColor
getSize
getHeight
getEyebrow
Bird
, excepto getHeight
.
Bird
llamado piolin
?
Bird instance piolin;
piolin class Bird;
piolin(Bird);
Bird piolin;
Bird::piolin
Bird piolin;
ya que la clase Bird
tiene un constructor que no requiere argumentos.
abelardo
es un objeto de tipo Bird
¿Cómo invocarías el método getSize
a abelardo
?
getSize.abelardo;
abelardo.getSize();
getSize(abelardo);
abelardo::getsize
Bird::abelardo.getSize()
abelardo.getSize();
. La sintaxis para invocar un método de un objeto es: NombreDelObjeto.NombreDelMetodo(parámetros)
.
cotorra
de la clase Bird
?
cotorra.setSize(10);
setSize(cotorra,10);
cotorra.setSize() = 10;
cotorra.size = 10
Bird::cotorra.setSize() = 10
cotorra.setSize(10);
. La sintaxis para invocar un método de un objeto es: NombreDelObjeto.NombreDelMetodo(parámetros)
. El método setSize()
requiere un argumento de tipo entero (que se provee entre los paréntesis).
Bird
?
Bird a(200);
Bird b;
Bird c(200, Bird::UPSET, “blue”, “red”);
Bird d(Bird);
Bird::f;
Bird
pasando un solo argumento. La clase Bird
tiene dos constructores: uno que no necesita recibir argumentos y otro que necesita recibir cuatro o cinco argumentos. La segunda opción: Bird b;
invocaría al constructor que no recibe argumentos. La tercera opción: Bird c(200, Bird::UPSET, “blue”, “red”)
invoca al constructor que recibe cuatro o cinco argumentos. Las otras dos opciones tampoco son válidas.
Sesión de laboratorio:
En la experiencia de laboratorio de hoy, utilizarás la clase Bird
para practicar la creación de objetos, acceder y cambiar sus atributos.
Ejercicio 1 - Estudiar la clase Bird
En este ejercicio te familiarizarás con la clase Bird
y con algunos métodos asociados a la clase MainWindow
que define la ventana en donde se despliegan resultados.
Instrucciones
Carga a
QtCreator
el proyectoBirds
. Hay dos maneras de hacer esto:- Utilizando la máquina virtual: Haz doble “click” en el archivo
Birds.pro
que se encuentra en el directorio/home/eip/labs/objects-birds
de la máquina virtual. - Descargando la carpeta del proyecto de
Bitbucket
: Utiliza un terminal y escribe el comandogit clone http://bitbucket.org/eip-uprrp/objects-birds
para descargar la carpetaobjects-birds
deBitbucket
. En esa carpeta, haz doble “click” en el archivoBirds.pro
.
- Utilizando la máquina virtual: Haz doble “click” en el archivo
Estudia la clase
Bird
contenida en el archivobird.h
. Identifica los métodos que son constructores, "setters" y "getters".Observa que en la clase se define un nuevo tipo llamado EyeBrowType cuyos valores pueden ser
UNI
,ANGRY
,UPSET
yBUSHY
. La función miembrosetEyebrow
recibe como parámetro un valor de tipo EyeBrowType. Si por ejemplo creas un objetobuho
de claseBird
y quieres cambiarle el tipo de cejas aBUSHY
debes hacerlo así:buho.setEyebrow(Bird::BUSHY);
- En el archivo
main.cpp
(en Sources) la funciónmain
hace lo siguiente:
a. Crea un objeto aplicación de Qt, llamado
a
. Lo único que necesitas saber sobre este objeto es que gracias a él es que podemos crear una aplicación gráfica en Qt e interaccionar con ella.b. Crea un objeto de la clase MainWindow llamado
w
. Este objeto corresponde a la ventana que verás cuando corras la aplicación.c. Inicializa la semilla del generador de números aleatorios de Qt. Esto hará que los pájaros nuevos tengan tamaños, colores y cejas aleatorias (a menos que los forcemos a tener valores específicos).
d. Invoca el método
show()
al objetow
. Esto logra que se muestre la ventana donde se desplegarán los resultados.e. En los programas que no tienen interfaz gráfica, la función
main()
usualmente termina con la instrucciónreturn 0;
. En este proyecto se utiliza la instrucciónreturn a.exec();
para que el objetoa
se haga cargo de la aplicación a partir de ese momento.- En el archivo
Compila y ejecuta el programa. Por ahora, solo debes obtener una ventana blanca (la ventana creada mediante el objeto
w
).
Ejercicio 2 - Crear objetos de clase Bird
con ciertos atributos
En este ejercicio crearás objetos de clase Bird
usando los constructores. También practicarás el uso de "getters" y "setters" para obtener y asignar atributos a los objetos.
Instrucciones
Crea un objeto de clase
Bird
llamadoabelardo
usando el constructor default. Añade aabelardo
a la ventanaw
usando el métodoaddBird(int x, int y, Bird b)
. Recuerda que la invocación del método debe comenzar con el nombre del objetow
y un punto.w.addBird(0,0,abelardo);
Corre varias veces el programa y maravíllate al ver a
abelardo
tener tamaños, colores y cejas distintas.Utiliza los "setters"
setSize(int size)
,setFaceColor(Qstring color)
,setEyeColor(Qstring color)
, ysetEyebrow(EyeBrowType)
para queabelardo
luzca como en la Figura 2 (su tamaño es 200).Figura 2. Abelardo.
Crea otro objeto de la clase Bird llamado
piolin
que tenga cara azul, ojos verdes, y cejas UNI invocando el constructorBird(int size, EyeBrowType brow, QString faceColor, QString eyeColor, QWidget *parent = 0)
. Su tamaño debe ser la mitad que el deabelardo
. Añádelo a la misma ventana donde se muestra aabelardo
usandow.addBird(300, 100, piolin)
para obtener una imagen como la que se muestra en la Figura 3.Figura 3. Abelardo y Piolin.
Crea otros dos objetos llamados
juana
yalondra
que salgan dibujados en las coordenadas (100, 300) y (300, 300) respectivamente. Crea ajuana
usando el constructor por defecto para que sus propiedades sean asignadas de forma aleatoria.Luego crea a
alondra
usando el otro constructor (el que recibe argumentos) para que puedas especificar sus propiedades durante su creación.alondra
debe ser igual de grande quejuana
, tener el mismo tipo de cejas, y el mismo color de ojos. Su cara debe ser blanca. Añade aalondra
y ajuana
a la misma ventana deabelardo
ypiolin
. La ventana debe ser similar a la de la Figura 4.Figura 4. Abelardo, Piolín, Juana y Alondra.
Corre varias veces el programa para asegurarte que
alondra
yjuana
siguen pareciéndose en tamaño, cejas y ojos.
Entregas
Utiliza "Entrega" en Moodle para entregar el archivo main.cpp
que contiene las invocaciones y cambios que hiciste al programa. Recuerda utilizar buenas prácticas de programación, incluye el nombre de los programadores y documenta tu programa.
Referencias
https://sites.google.com/a/wellesley.edu/wellesley-cs118-spring13/lectures-labs/lab-2