Diario
de un programador. Día 190
La
interfaz de una clase:
Una interfaz nos permite poder interactuar con un sistema,
cualquiera que sea. Por ejemplo, un televisor puede poseer botones, los cuales
funcionan como una interfaz entre nosotros y los componentes internos del
televisor. El televisor podría tener un
botón para ajustar el volumen, otro para cambiar de canal, otro para encender
el televisor, etc.
Otro ejemplo de interfaz podría ser un horno microondas, el cual
posee botones o perillas para ajustar el tiempo, la temperatura, etc. Otro
ejemplo de interfaz sería una lavadora, con botones para ajustar el tipo de
lavado, cantidad de agua, tipo de ropa etc.
Así como estos ejemplos hay muchos, lo importante es saber que una
interfaz nos permite saber o especificar qué operaciones podemos hacer (cambiar
de canal, ajustar temperatura, encender, apagar, etc.), pero no cómo funcionan estas operaciones, en
otras palabras, una interfaz no indica o muestra cómo es que el control de
volumen realiza internamente esa operación. Una interfaz es como un menú de
opciones, el usuario escoge una opción y el programa realiza lo que hemos
seleccionado. En informática, una interfaz se compone de menús desplegables,
botones, íconos, barras de desplazamiento, ventanas, opciones, etc.
La interfaz de una clase se compone por funciones miembro public de
la clase.
Con lo anterior dicho, puede surgir la pregunta ¿cómo separar la
interfaz de la implementación?
Hasta ahora, la definición de cada clase que hemos hecho contiene
las definiciones completas de las funciones miembro public de la clase y las
declaraciones de sus miembros de datos private. A pesar de que los programas
funcionan de esa manera, una mejor ingeniería de software es definir las
funciones miembro fuera de la definición de la clase, para así poder ocultar su
implementación. Aprender a trabajar de este modo es útil cuando se trabaja en
un grupo de personas, así nos aseguramos que los programadores no escriban
código que dependa de los detalles de implementación de la clase, de lo
contrario, se corre el riesgo de que el código cliente falle si cambia la
implementación de la clase.
Para lograr lo anterior, lo que debemos hacer es dividir nuestro
programa en distintos archivos. Vamos a crear un archivo de encabezado .h
donde definiremos una clase (esta será
nuestra interface), y dos archivos .cpp, uno de código fuente, en el que
definiremos las funciones miembro y el
otro archivo .cpp define el código cliente (la función main).
Antes que nada, para que estos tres archivos se puedan enlazar, (y no muestre un error al momento de compilar)
en code blocks debemos crear un proyecto.
Para crear un proyecto, debemos hacer lo siguiente:
Desde el menú File, escoger New y luego seleccionar Project...
Luego, seleccionar Empty project y posteriormente presionar el botón
Go.
En la siguiente ventana, presionamos Next.
Ahora se debe seleccionar un título para el proyecto y seleccionar
la carpeta donde se guardará nuestro proyecto. Luego presionar Next.
Luego debemos seleccionar el compilador, dejamos GNU GCC Compiler
que viene por defecto. Luego nos pide seleccionar al menos UNA configuración.
(por defecto vienen seleccionadas las dos) Estas configuraciones son Debug y
Release. Principalmente la opción Debug es para obtener un proyecto que se
pueda depurar y Release, es básicamente el proyecto ya listo para salir
"al mercado", es decir, un proyecto ya depurado y revisado. Como esto
es algo que veremos más adelante, simplemente lo dejaremos tal como está y
seleccionaremos el botón Finish.
Ahora vamos a crear nuestro primer archivo, el cual será el archivo
de cabecera .h, para ello seleccionamos el ícono de New File y seleccionamos
Empty file.
Nos va a preguntar si queremos añadir este nuevo archivo al
proyecto. Nosotros seleccionamos que sí.
Ahora nos pide que guardemos nuestro archivo. Para este ejemplo,
nuestro primer archivo se llamará interface.h
Ahora nos preguntará a cual configuración pertenecerá el archivo,
por defecto estarán seleccionadas ambas opciones. Dejaremos esto así por ahora
y seleccionaremos el botón Ok.
Ahora sí, ya estamos listos para crear nuestro primer archivo, que
como dijimos antes será el archivo de cabecera .h. Este archivo será nuestra
interface y por ser un ejemplo, empezare mostrando un programa muy básico. Este
solamente mostrará un mensaje por pantalla, pero será suficiente para ver cómo
funciona esto.
El código es el siguiente:
//interface.h
#include<iostream>
#include <string>
using std::string;
class ClaseMensaje{
public:
ClaseMensaje(string);
void setPalabra(string);
string getPalabra();
private:
string
mensaje;
};
La interface que
se presenta, tiene una clase llamada ClaseMensaje. Dentro de esta clase lo que
hacemos es definir los prototipos. Estos prototipos son los que conforman la
interfaz, bastante sencilla pero es una interfaz.
El primer
prototipo, ClaseMensaje(string)
corresponde al constructor de la clase, el cual recibe un parámetro de tipo
string. El segundo prototipo, void
setPalabra(string), corresponde a la función que se encargará de establecer
la palabra o mensaje que seleccionaremos más adelante. Este prototipo indica
que la función recibe un parámetro de tipo string. El tercer prototipo, void getPalabra(string), corresponde a
la función que se encargará de recuperar la palabra o mensaje que fue
anteriormente seleccionada. Posteriormente tenemos una variable de tipo string,
llamada mensaje, la cual será
ocupada para almacenar el mensaje seleccionado.
Ahora que ya está
lista la interface, pasaremos a crear las funciones en otro archivo. El archivo
que se creará lo llamaremos funciones.cpp.
El código es el siguiente:
//funciones.cpp
#include "interface.h"
using std::string;
ClaseMensaje::ClaseMensaje(string palabra){
setPalabra(palabra);
}
void
ClaseMensaje::setPalabra(string palabra){
mensaje = palabra;
}
string
ClaseMensaje::getPalabra(){
return
mensaje;
}
En este código se
implementan las funciones que vamos a utilizar. Al principio de este código, se
debe incluir la directiva del preprocesador #include "interface.h".
Más abajo, tenemos el constructor de la clase, el cual utiliza el signo ::,
este signo se conoce con el nombre de operador
binario de resolución de ámbito. Este sirve para enlazar la interfaz. De no
usarlo, entonces el programa produciría un error ya que el compilador no
reconocería las funciones. La forma que se muestra para utilizarlo es
escribiendo el nombre de la clase que se va a enlazar (que en este caso es la
clase ClaseMensaje)seguido de los operador :: y posteriormente el nombre de la
función. A parte de esta nueva implementación, las funciones están formadas
normalmente. Si se presta atención, se puede ver que las funciones set y get no
presentan mayores cambios.
Ya por último
vamos a crear la función main. Esta función, como se puede apreciar más abajo,
no contiene nada nuevo. Aquí simplemente creamos un objeto de la clase
ClaseMensaje, el cual le pasamos como parámetro la palabra "Buenas
noches"
//inicio.cpp
#include <iostream>
#include "interface.h"
using std::cout;
int main()
{
ClaseMensaje
saludo("Buenas noches");
cout <<
saludo.getPalabra();
return 0;
}
Al compilar y ejecutar el
programa, se puede apreciar el resultado
Otro ejemplo similar, pero esta vez solicitando datos
sería el siguiente:
Al igual que el anterior ejemplo, aquí empezamos
escribiendo la interfaz. Esta quedaría de la siguiente manera:
El código que contiene las funciones quedaría de la siguiente
manera:
Y por último, el código main, quedaría de la siguiente manera:
Entonces, al compilar y ejecutar el programa, se obtendría el
siguiente resultado:
Bueno, esto es todo por ahora.
Saludos.
Gustavo J. Cerda Nilo
Noviembre 2016