PLE:UnidadT

1. INTRODUCCIÓN - ¿ QUE ES VISUAL C++ ?

Como sabemos, Windows es el entorno más popular de interfaz gráfico de usuario (GUI). Desde este punto de vista, Windows es un entorno multitarea basado en ventanas, que representan programas, y que permite ejecución concurrente.

Para desarrollar programas, Windows provee una librería de rutinas y funciones (SDK - Kit de desarrollo de software) que permiten gestionar componentes como menús, diálogos, ventanas, etc.

Visual C++ es un entorno integrado de desarrollo que permite la programación orientada a objetos (POO) conjuntamente con el sistema de desarrollo SDK (también denominado API) de Windows. Al ser un entorno integrado Visual C++ incluye, entre otras, las siguientes herramientas de desarrollo:

* Editor de texto

* Compilador/Enlazador

* Depurador

* Visor de datos y dependencias (Browser)

Pero si desde el punto de vista del usuario Windows es un sistema amigable, desde el punto de vista del desarrollador observaremos todo lo contrario. El SDK de Windows no es mas que un complejo conjunto de funciones que añade además numerosas definiciones de tipos de datos nuevos para cualquier programador de C/C++ para DOS. Para solucionar este problema, Visual C++ incluye la librería de clases MFC (Microsoft Foundation Classes) que permite crear y gestionar de manera intuitiva componentes típicos de Windows. Esto es, la MFC es una implementación que utiliza el API encapsulando todas las estructuras y llamadas a funciones en objetos fáciles de utilizar. Basándose en la potencia de la MFC, Visual C++ se convierte en un generador de programas C++ para Windows.

El objetivo del presente curso es conocer el modelo de programación para Windows basado en la librería de clases MFC. En este documento se destacarán ideas, conceptos y tratamientos generales, en ningún momento pretende ser un manual completo de programación con MFC.

1. CONCEPTOS PRELIMINARES

1. ¿ Que es C ++ ?

Como todos sabemos, "C" es un lenguaje de alto nivel, basado en funciones, que permite desarrollos estructurados. Entre otras muchas características contempla la definición de estructuras de datos, recursividad o indirecciones a datos o código (punteros).

"C ++", por su parte, es un superconjunto de "C", al que recubre con una capa de soporte a la POO. Permite por tanto la definición, creación y manipulación de objetos.

2. ¿ Que es la Programación Orientada a Objetos ?

La POO es una nueva filosofía de programación que se basa en la utilización de objetos. El objetivo de la POO no es sino la meta de cualquier modelo de programación estructurada convencional: "imponer" una serie de normas de desarrollo que aseguren y faciliten la mantenibilidad y reusabilidad del código.

Los mecanismos básicos de la POO son: objetos, mensajes, métodos y clases.

* Objetos. Un objeto es una entidad que tiene unos atributos particulares (datos) y unas formas de operar sobre ellos (los métodos o funciones miembro). Es decir, un objeto incluye, por una parte una serie de operaciones que definen su comportamiento, y una serie de variables manipuladas por esas funciones que definen su estado. Por ejemplo, una ventana Windows contendrá operaciones como "maximizar" y variables como "ancho" y "alto" de la ventana.

* Mensajes. En C++, un mensaje se corresponde con el nombre de uno de los métodos de un objeto. Cuando se pasa un mensaje a un objeto, este responde ejecutando el código de la función asociada.

* Método. Un método (función miembro) se implementa dentro de un objeto y determina como tiene que actuar el objeto cuando se produce el mensaje asociado. En C++ un método se corresponde con la definición de la función miembro del objeto. La estructura más interna de un objeto está oculta, de tal manera que la única conexión con el exterior son los mensajes

* Clases. Una clase es la definición de un tipo de objetos. De esta manera, una clase "Empleado" representaría todos los empleados de una empresa, mientras que un objeto de esa clase (también denominado instancia) representaría a uno de esos empleados en particular.

Las principales características de la POO son: abstracción, encapsulamiento, herencia y polimorfismo:

* Abstracción. Es el mecanismo de diseño en la POO. Nos permite extraer de un conjunto de entidades datos y comportamientos comunes para almacenarlos en clases.

* Encapsulamiento. Mediante esta técnica conseguiremos que cada clase sea una caja negra, de tal manera que los objetos de esa clase se puedan manipular como unidades básicas. Los detalles de la implementación se encuentran dentro de la clase, mientras que desde el exterior, un objeto será simplemente una entidad que responde a una serie de mensajes públicos (también denominados interfaz de la clase).

* Herencia. Es el mecanismo que nos permite crear clases derivadas (especialización) a partir de clases bases (generalización). Es decir, podríamos tener la clase "Empleado" (clase base) y la clase "Vendedor" derivando de la anterior. Una librería de clases (como la MFC) no es más que un conjunto de definiciones de clases interconectadas por múltiples relaciones de herencia.

* Polimorfismo. Esta característica nos permite disponer de múltiples implementaciones de un mismo método de clase, dependiendo de la clase en la que se realice. Es decir, podemos acceder a una variedad de métodos distintos (con el mismo nombre) mediante el mismo mecanismo de acceso. En C++ el polimorfismo se consigue mediante la definición de clases derivadas, funciones virtuales y el uso de punteros a objetos.

Otros dos conceptos muy importantes en la POO son relativos a la creación y destrucción de objetos. En lenguajes estructurados convencionales, cuando se define una variable se le reserva espacio en memoria y, si no se inicializa expresamente, se hace por defecto (por ejemplo, en C una variable global siempre se inicializa a 0, pero una automática no, por lo que si no se inicializa expresamente su contenido inicial será basura); por otra parte, cuando se destruye una variable (por que se abandona el ámbito de su definición - scope -) se libera la memoria que estaba ocupando. Si ahora hacemos el paralelismo obligado entre variables y objetos para los lenguajes POO nos daremos cuenta de que deben existir procedimientos especiales de construcción y destrucción de objetos. En concreto, cada clase tiene dos funciones miembro especiales denominadas constructor y destructor.

* Constructor -> Función miembro que es automáticamente invocada cada vez que se define un objeto, su objetivo es la inicialización del mismo. Toma el mismo nombre que la clase, puede recibir parámetros y podemos tener varios constructores definidos.

* Destructor -> Función miembro invocada automáticamente cada vez que se destruye un objeto. Su objetivo es realizar operaciones como liberación de memoria, cerrar ficheros abiertos, etc. Toma el mismo nombre de la clase comenzado primero por el carácter "~", no toma parámetros y no admite la sobrecarga (sólo puede existir uno en cada clase).

En muchos casos, para las clases mas sencillas, podemos encontrar clases que no tiene constructor o destructor, ó ninguno de los dos. En C++, siempre existen constructores y destructores por defecto que realizan una inicialización/liberación estándar.

1. El modelo de programación Windows

El modelo de programación propuesto por Windows es totalmente diferente al modelo de ejecución secuencial de DOS. Al ser Windows un entorno multitarea los programas tienen que estar preparados para compartir los recursos de la maquina (procesador, memoria, teclado, ratón …). Esto supone que Windows ha de disponer de métodos que permitan suspender tareas para activar otras en función de las circunstancias del momento (por ejemplo, por acción del usuario).

Pero por parte de las aplicaciones, este hecho supone que han de cooperar en la compartición de esos recursos. Las aplicaciones Windows se limitan a "esperar" mensajes procedentes del sistema, procesarlos y volver al estado de espera. Este modelo de programación se conoce como "orientado al evento".

* Mensaje. Es una notificación a la aplicación de que ha ocurrido algo de interés y que por lo tanto debe de realizarse alguna acción específica. El origen del mensaje puede ser el usuario (haciendo click con el ratón dentro e una ventana), la propia aplicación (mandándose un mensaje a si misma) o Windows (pidiendo, por ejemplo, que se repinte la ventana tras ocultarse otra que tuviese delante). Dado que la unidad mínima de ejecución en Windows es una ventana, los mensajes van realmente dirigidos a ellas.

* Ventana y procedimiento de ventana. En Windows, una aplicación se representa físicamente por su ventana principal (aunque después pueda desplegar diversas ventanas hijas). Cada una de esas ventanas dispone de una serie de propiedades y un código asociado (lo que concuerda con el principio de la POO, en el concepto de objeto). Al código asociado a cada ventana se le denomina procedimiento de ventana. Es una función que recibe los mensajes, los procesa y devuelve el control a Windows para quedar en espera.

Otra de las características específicas de Windows frente a DOS es el uso de recursos por parte de las aplicaciones, como son iconos, menús, mapas de bits, cursores, plantillas de diálogos, etc. Las aplicaciones Windows disponen por tanto de recursos (gráficos generalmente) propios almacenados en lo que se llama el fichero de recursos). El proceso de construcción de programas en Windows incorpora una fase adicional al compilado y enlazado de los módulos objeto y las librerías. Hay un proceso final de compilación y de enlazado (bind) del fichero de recursos.

3. EL ENTORNO DE DESARROLLO - INTRODUCCIÓN.

El entorno de desarrollo viene representado por el icono "Developer Studio". En él se integran entre otras las siguientes herramientas:

* Editor orientado a la codificación C/C++ (resaltando palabras claves …)

* Compilador/Enlazador incremental, que acelera el proceso de construcción de los programas.

* Depurador visual, que permite visualizar y modificar el contenido de variables y áreas de memoria.

* Visor de datos (browser) que permite fácilmente controlar dependencias y referencias a funciones, datos, clases, etc. Además permite visualizar la jerarquía de las clases utilizadas en los programas.

* Herramientas complementarias como un analizador de ventanas (Spy ++) o un trazador de funciones MFC.

1. El concepto de proyecto (workspace)

En Visual C++ la construcción de cualquier tipo de programa se inscribe dentro del concepto de proyecto (workspace). Un proyecto define los pasos a seguir para alcanzar la construcción de un objetivo (un programa, una DLL, etc.), en realidad es un concepto análogo a lo que se conoce como "makefile" en otros entornos típicos de desarrollo en C. En realidad, Visual C++ genera para cada proyecto dos ficheros que lo definen, el fichero de workspace (con extensión wsp) y un makefile (con extensión mak) estándar que permitiría la utilización del mismo proyecto en otro entorno distinto.

Desde el punto de vista funcional, el proyecto contiene referencias a cada uno de los ficheros fuentes (C/C++, con extensiones c y cpp respectivamente), objetos, librerías o ficheros de recursos (extensión rc) que se deben utilizar para construir el objetivo final del proyecto.

En definitiva, para crear cualquier programa con Visual C++ debemos comenzar creando un proyecto para él, codificando y añadiendo los módulos necesarios a dicho proyecto, y definiendo los recursos asociados.

2. Posibilidades de programación

Cuando se crea un nuevo proyecto (desde la opción "Nuevo" del menú "Fichero" aparece un diálogo que nos permite especificar que se cree un nuevo workspace), lo primero que solicita el sistema es determinar el tipo de objetivo que se persigue con este proyecto. Destacar las siguientes posibilidades:

* Aplicación (.EXE) basada en la MFC (MFC AppWizard)

* Librería de enlace dinámico (.DLL) basada en la MFC. (MFC AppWizard)

* Aplicación (.EXE) estándar para Windows (basada en el SDK)

* Librería de enlace dinámico (.DLL) (basada en el SDK)

* Aplicación (.EXE) modelo DOS (Console application)

* Librería estática (.LIB)

Como ya hemos destacado anteriormente, el objetivo del presente curso es el manejo de la librería MFC, por lo que nos centraremos básicamente en el primer punto (la construcción de una DLL con MFC es totalmente similar).

1. EL GENERADOR DE APLICACIONES.

Ya sabemos que Visual C++, apoyado en la potencia de la MFC, es capaz de convertirse en un generador de aplicaciones. Para ello dispone de dos herramientas integradas complementarias:

* AppWizard, que es el generador de aplicaciones propiamente dicho. Con él podremos generar esqueletos de programas para Windows basados en la MFC.

* ClassWizard, herramienta de mantenimiento de los programas generados con la anterior. Permite añadir o eliminar clases, modificar los comportamientos de las mismas, etc.

Pero el código generado mediante este método presenta una complejidad añadida a la natural de cualquier programa; junto con el código C/C++ y el de la MFC aparecen líneas (generalmente entre comentarios) que son totalmente necesarias para el funcionamiento de las dos herramientas anteriores, modificar cualquiera de esas líneas de código dará muchos problemas a la hora de utilizar ClassWizard para modificarlo. De todas maneras, este "defecto" es bastante popular entre los usuarios de cualquier generador de código, para cualquier lenguaje.

El formato general de los proyectos generados con estas herramientas suele tener las siguientes características:

* Cada clase de nuestro programa dispondrá de dos ficheros: Un fichero de cabecera (extensiones .h o .hpp) y un fichero de implementación (.cpp). El fichero de cabecera contiene la definición de la clase (definiciones de sus miembros datos y funciones - los mensajes -), mientras que el fichero fuente contiene la implementación de esas funciones miembro (los métodos de la clase).

* Un fichero de recursos (extensión .rc), aunque éste es opcional.

* Módulos objetos (.obj) y librerías estáticas (.lib) necesarias para crear nuestro programa.

1. CONSTRUCCIÓN DE UNA APLICACIÓN BÁSICA

Seguiremos los siguientes pasos:

1. Crear un nuevo proyecto. Desde el menú "Fichero", en la opción "Nuevo".

1. Seleccionar objetivo del proyecto. Seleccionaremos "aplicación basada en MFC"

1. Nombrar el proyecto. Visual C++ organiza los proyectos de manera que crea un subdirectorio nuevo con el nombre de cada proyecto. Aunque esta "regla" siempre puede modificarse, puede ser una buena forma de control de proyectos.

En estos momentos aparecerá la secuencia de diálogos del generador ClassWizard. Veamos cuales serían los pasos a seguir para crear una aplicación sencilla:

1. Paso 1. Permite identificar el modelo de ventana principal de nuestra aplicación: SDI, MDI o basada en diálogo. Nosotros elegiremos SDI.

1. Paso 2. Permite incorporar soporte a Bases de Datos en la aplicación. Esto lo veremos más adelante. Seleccionaremos la opción sin soporte a bases de datos.

1. Paso 3. Relativo al soporte OLE. Igual que en el caso anterior.

1. Paso 4. Otras características de la aplicación (barra de botones, barra de estado, controles 3D …)

1. Paso 5. Generación de comentarios en el código (si/no) y usos posibles de las MFC (como DLL o como LIB). Se recomienda la opción DLL en cuanto al tamaño y modularidad del programa, pero deberemos asegurarnos de distribuir la DLL junto con nuestro programa para que funcione correctamente.

1. Paso 6. Permite modificar el nombre de las clases MFC que se van a generar, además de especificar los ficheros en los que se implementa y la clase base de la que derivan. Los nombres generados por AppWizard suelen ser bastantes significativos.

A partir de este momento da comienzo la generación del código definido antes. Como se habrá observado, el nombre por defecto de las clases generadas tiene mucho que ver con el nombre que le hayamos dado al proyecto. De esta manera, si hubiésemos llamado "curso1" al proyecto tendríamos la siguiente situación:

* Clase CCurso1App (módulos curso1.h y curso1.cpp) que representa una aplicación Windows.

* Clase CMainFrame (ficheros mainfrm.h y mainfrm.cpp) que representan la ventana principal de la aplicación.

* Clases CCurso1Doc y CCurso1View (ficheros curso1doc.h/curso1doc.cpp y curso1view.h/curso1view.cpp respectivamente), representantes de lo que se conoce en el mundo Windows como interfaz "Documento/Vista" y que trataremos en adelante.

* Clase CAboutDlg que representa el típico diálogo de "Acerca de …" y que ha sido generado automáticamente por AppWizard, esta clase (rompiendo la norma habitual de la MFC) aparece definida e implementada dentro los mismos ficheros que la clase aplicación (módulos curso1.h y curso1.cpp). En el futuro evitaremos este tipo de construcciones.

Cada una de estas clases se revisará con detalles en capítulos sucesivos.