UNIVERSIDAD PONTIFICIA COMILLAS ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI) INGENIERO EN INFORMÁTICA PROYECTO FIN DE CARRERA PROGRAMACIÓN ORIENTADA A OBJETOS MEDIANTE MINGW DEVELOPER STUDIO AUTOR: JACOBO IGLESIAS JATO MADRID, Septiembre de 2008 Autorizada la entrega del proyecto del alumno: Jacobo Iglesias Jato EL DIRECTOR DEL PROYECTO Eduardo Alcalde Lancharro Fdo.: ……………………… Fecha: 05/ 09 / 08 VºBº DEL COORDINADOR DE PROYECTOS Eduardo Alcalde Lancharro Fdo.: ……………………… Fecha: 12/ 09/ 08 El verdadero progreso es el que pone la tecnología al alcance de todos. Henry Ford. (1863-1947) Programación Orientada a Objetos en C mediante MinGW Developer Studio. AGRADECIMIENTOS A mis padres, por darme la oportunidad de demostrar mi valía y por su gran apoyo económico y emocional durante estos cinco años de carrera. A mis hermanos, por su apoyo incondicional en los buenos y malos momentos. A Jaime, Luis y Nico, porque durante estos años han estado siempre ahí y han hecho de ellos una etapa inolvidable en mi vida. A Alba, por aguantarme y confiar en mí durante todo este tiempo. A Edu, por su apoyo y confianza durante estos últimos años. Al Director del proyecto, Eduardo, por su cercanía e inestimable ayuda a la hora de desarrollar este proyecto. A Santiago Canales, porque sin su apoyo en aquellos primeros momentos difíciles no habría alcanzado la meta. I Programación Orientada a Objetos en C mediante MinGW Developer Studio. RESUMEN Se ha realizado un estudio y análisis detallado del compilador de libre difusión (freeware) MinGW Developer Studio. Dado que este compilador es freeware, se puede descargar de la red sin ningún coste si bien no trae documentación alguna. Esto es debido a que, al ser gratuito, se facilita su uso y expansión pero carece de documentación o manual de ayuda al usuario. Por esta razón se ha realizado un análisis profundo del compilador en el que se especifican todos los aspectos que faciliten al usuario su utilización como herramienta software de procesamiento de programas en los lenguajes C y C++. En el proyecto se ha llevado a cabo una explicación del entorno de desarrollo del compilador, del proceso de creación de aplicaciones, de la estructura del programa y del proceso de depuración de aplicaciones. Además, se han explicado en detalle los diferentes comandos existentes en el menú de la aplicación así como las diferentes barras que componen la interfaz. El estudio del funcionamiento del compilador en la parte que se corresponde a Orientación a Objetos también ha sido objeto de estudio del proyecto. Para ello se han explicado los diferentes conceptos clave propios de la Programación Orientada a Objetos (POO) así como los principales paradigmas que caracterizan a este enfoque de programación. Para poder llevar a cabo POO en MinGW Developer Studio es preciso emplear el lenguaje de programación C++. Este lenguaje permite programar tanto en estilo procedimental (orientado a algoritmos), como en estilo orientado a objetos, como en ambos a la vez. Por ello, se han estudiado todas las opciones que ofrece este lenguaje en cuanto a Orientación a Objetos así como las opciones que ofrece el compilador para permitir programar empleando el citado lenguaje de programación. II Programación Orientada a Objetos en C mediante MinGW Developer Studio. El estudio de las librerías gráficas del compilador para permitir desarrollar interfaces gráficos de usuario (GUI) es otro de los aspectos que se abordan en el proyecto. Para ello, se ha explicado en detalle el proceso de creación de ventanas, así como el manejo de algunos elementos básicos como cuadros de diálogo o menús. Para poder llevar a cabo programación de interfaces gráficas de usuario (GUI) en MinGW Developer Studio es preciso emplear el API de Windows (WinAPI), que es un conjunto de interfaces de programación de aplicaciones (application programming interfaces - API) de Microsoft disponible en los sistemas operativos Microsoft Windows. III Programación Orientada a Objetos en C mediante MinGW Developer Studio. ABSTRACT A detailed study and analysis about the freeware compiler MinGW Developer has been carried out in this project. Though this is a freeware compiler, it can be downloaded for free from the Internet without any additional costs but it does not include any documentation. This is due to the fact that being freeware makes its use and expansion easier but it lacks documentation or user help manual. For this reason, an exhaustive compiler analysis has been carried out where all the aspects that make its use as a C and C++ programs processing software tool easier are specified. A detailed explanation about several aspects of the compiler has also been carried out. Aspects such as the development environment, the applications creation process, program structure and applications debugging have been explained in a thorough way. All the different commands and bars that make the interface up have also been described. The running of the compiler in the part related to Object Oriented Programming (OOP) has also been studied. For that reason, all the different basic concepts about OOP have been explained as well as the main programming paradigms that characterize this programming approach. It is necessary to use C++ programming language to carry out OOP in MinGW Developer Studio. This language makes possible for users to program in procedural style (algorithm oriented programming) and also in object oriented style, as well as both at the same time. Due to that, all the options that this language offers related to Object Orientation have been studied as well as all the alternatives that this compiler offers to allow programming using the aforementioned programming language. The study of the compiler’s graphic libraries that make graphical user interfaces (GUI) development possible is another aspect that has been tackled IV Programación Orientada a Objetos en C mediante MinGW Developer Studio. in the project. Therefore, the windows creation process as well as the use of some basic elements such as dialog boxes or menus has also been explained in detail. To carry out graphical user interfaces (GUI) programming in MinGW Developer Studio it is necessary to use Windows API (WinAPI), which is a group of Microsoft’s application programming interfaces available in all Microsoft Windows operative systems. V Programación Orientada a Objetos en C mediante MinGW Developer Studio. ÍNDICE PARTE I: Estudio del compilador ................................................................... 1 1. Entorno de desarrollo de MinGW Developer Studio ................................. 2 2. Iniciar MinGW Developer Studio ............................................................... 5 2.1. Descarga e instalación de MinGW Developer Studio ...................... 6 2.2. Iniciar MinGW Developer Studio...................................................... 8 3. Crear una aplicación en lenguaje de programación C ............................ 10 4. Estructura del entorno de desarrollo de MinGW Developer Studio ......... 14 4.1. Zonas principales .......................................................................... 15 4.1.1. Zona de workspace ................................................................. 15 4.1.2. Zona de edición ....................................................................... 21 4.1.3. Zona de salida ......................................................................... 23 4.2. Barras de tareas ............................................................................ 27 4.2.1. Menú principal ......................................................................... 27 4.2.2. Barra de herramientas ............................................................ 66 5. Depuración de programas (Debugging) .................................................. 67 5.1. Menú Debug .................................................................................. 69 PARTE II: Funcionamiento del compilador en la parte que corresponde a Orientación a Objetos (C++) ................................................. 79 1. Introducción ............................................................................................ 80 2. Creación de aplicaciones C++ en MinGW Developer Studio .................. 84 2.1. Opciones de MinGW Developer Studio relacionadas con C++ ..... 88 3. Programación Orientada a Objetos (POO) en C++ ................................. 90 3.1. Clase ............................................................................................. 93 3.2. Constructor y destructor ................................................................ 95 3.3. Creación de objetos....................................................................... 96 3.4. Especificadores de acceso ............................................................ 98 3.5. Ficheros de cabecera y espacio de nombres ................................ 99 3.6. Ejemplo de aplicación orientada a objetos mediante MinGW Developer Studio ......................................................................... 101 VI Programación Orientada a Objetos en C mediante MinGW Developer Studio. 3.7. Operadores de entrada/salida ..................................................... 103 3.8. Modificadores .............................................................................. 105 3.9. Variable reservada this ................................................................ 107 3.10. Métodos inline ............................................................................. 109 3.11. Clases y métodos friend .............................................................. 110 4. Paradigmas de programación ............................................................... 113 4.1. Encapsulamiento ......................................................................... 114 4.2. Ocultación.................................................................................... 116 4.3. Abstracción .................................................................................. 117 4.4. Herencia ...................................................................................... 118 4.4.1. Herencia múltiple .................................................................. 127 4.5. Polimorfismo ................................................................................ 128 4.5.1. Implementación de los métodos virtuales ............................. 131 4.5.2. Métodos virtuales puros ........................................................ 133 4.5.3. Clases abstractas .................................................................. 134 4.5.4. Destructores virtuales............................................................ 135 PARTE III: Estudio de las librerías gráficas del compilador para permitir desarrollar interfaces gráficas de usuario (GUI) ............................ 136 1. Introducción .......................................................................................... 137 2. API de Windows (WinAPI) .................................................................... 140 2.1. Introducción ................................................................................. 141 2.2. Características de la programación en Windows ......................... 143 2.2.1. Independencia de la máquina ............................................... 143 2.2.2. Recursos ............................................................................... 143 2.2.3. Ventanas ............................................................................... 144 2.2.4. Eventos ................................................................................. 144 2.2.5. Controles ............................................................................... 146 2.3. Creación de proyectos WinAPI en MinGW Developer Studio...... 147 2.4. Componentes de una ventana..................................................... 150 2.5. Notación húngara ........................................................................ 152 2.6. Estructura de un programa Windows GUI ................................... 154 VII Programación Orientada a Objetos en C mediante MinGW Developer Studio. 2.6.1. Cabeceras ............................................................................. 154 2.6.2. Prototipos .............................................................................. 155 2.6.3. Función de entrada WinMain ................................................ 155 2.6.3.1. Parámetros de entrada de WinMain ............................. 155 2.6.3.2. Función WinMain típica................................................. 156 2.6.3.3. Declaración ................................................................... 158 2.6.3.4. Inicialización ................................................................. 158 2.6.3.5. Bucle de mensajes ....................................................... 159 2.6.4. Definición de funciones ......................................................... 159 2.7. El procedimiento de ventana ....................................................... 160 2.7.1. Sintaxis.................................................................................. 160 2.7.2. Prototipo de procedimiento de ventana ................................. 161 2.7.3. Implementación de procedimiento de ventana simple........... 161 2.8. Ejemplo GUI mediante MinGW Developer Studio ....................... 162 3. Menús y cuadros de diálogo ................................................................. 165 3.1. Menús ............................................................................................. 166 3.1.1. Función MessageBox ............................................................ 170 3.1.2. Ejemplo completo de menús y cuadros de mensaje ............. 174 3.2. Cuadros de diálogo ........................................................................ 178 3.2.1. Procedimiento de diálogo ...................................................... 181 3.2.2. Paso de parámetros a un cuadro de diálogo......................... 185 3.2.3. Ejemplo completo de cuadros de diálogo.............................. 189 4. Creación de recursos mediante el editor de recursos ........................... 194 PARTE IV: Valoración y conclusiones........................................................ 203 1. Valoración económica y planificación ................................................... 204 1.1. Valoración económica ................................................................. 205 1.1.1. Coste de tecnología .............................................................. 205 1.1.2. Coste de implantación ........................................................... 206 1.2. Planificación del proyecto ............................................................ 208 2. Conclusiones ........................................................................................ 210 3. Bibliografía ............................................................................................ 213 VIII Programación Orientada a Objetos en C mediante MinGW Developer Studio. PARTE I: Estudio del compilador -1- Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 1 Entorno de desarrollo de MinGW Developer Studio -2- Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 1. Entorno de desarrollo de MinGW Developer Studio. El compilador MinGW Developer Studio es de libre difusión (freeware), esto es, puede descargarse de forma gratuita desde la página web de Parinya (www.parinyasoft.com) en las siguientes versiones: Nombre Fichero MinGWStudioFullSetup2_05.exe Tamaño Sistema (MB) Operativo 26 Windows Versión 2.05 Fecha de creación 01-042005 Contenido Entorno de desarrollo y compilador. Entorno de desarrollo y compilador. Incluye MinGWStudioFullSetupPlus2_05.exe 125 Windows 2.05 01-042005 además las librerías wxWidgets 2.6.0 para crear entornos gráficos. Mingw-devstudio_linux2.06.tar.gz 2 Linux 2.06 08-072005 Entorno de desarrollo y compilador. Además, en caso de descargarse para el sistema operativo Windows Vista es necesario llevar a cabo los siguientes pasos: • Después de instalar el compilador se debe editar la variable de entorno PATH. Esto se hace en Panel de control Sistema Configuración avanzada del sistema Propiedades del sistema Opciones avanzadas Variables de entorno. -3- Programación Orientada a Objetos en C mediante MinGW Developer Studio. • Añadir a la variables de entorno PATH los siguientes directorios: C:\MinGWStudio;C:\MinGWStudio\MinGW\bin;C:\MinGWStudio\MinGW\lib\gcc\mingw32\3.4.2 -4- Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 2 Iniciar MinGW Developer Studio -5- Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 2. Iniciar MinGW Developer Studio. Antes de explicar el inicio del entorno de desarrollo de MinGW Developer Studio se explicarán los pasos que hay que dar a la hora de descargar e instalar el software. 2.1. Descarga e instalación de MinGW Developer Studio. Para descargar el programa se accede a la página Web de Parinya (www.parinyasoft.com). En el apartado “Download” aparecen una serie de versiones del software que se pueden descargar. La versión que se recomienda descargar es la número 3 de MS-Windows por ser la más completa y la que incluye todas las herramientas disponibles para el software. Se descarga, por tanto, el fichero MinGWStudioFullSetupPlus-2_05.exe. Una vez descargado el fichero de instalación, se ejecuta y aparece un asistente de descarga del software llamado “Simtel Downloader”. -6- Programación Orientada a Objetos en C mediante MinGW Developer Studio. Una vez que el asistente de descarga alcanza el 100% de progreso aparece el asistente de instalación de MinGW Developer Studio. Se pulsa el botón “Next” y se siguen los pasos del asistente en los que se solicitará la aceptación de los términos de licencia, la selección de los componentes a instalar y el directorio de instalación. Una vez instalado el software tras pulsar el botón “Install” aparece una ventana de confirmación de instalación donde aparecen marcadas por defecto las opciones “Show Readme” para ver los créditos del software y “Run MinGW Developer Studio 2.05” para -7- Programación Orientada a Objetos en C mediante MinGW Developer Studio. ejecutar la aplicación. Se desactivan las opciones que no interesen y se pulsa el botón “Finish”. En este momento el software ya estará instalado. 2.2. Iniciar MinGW Developer Studio. Para iniciar el entorno de desarrollo de MinGW Developer Studio se hace lo siguiente: i. En el escritorio de Windows, se sitúa el puntero del ratón en el menú Inicio, en la esquina inferior izquierda, y se pulsa el botón izquierdo del ratón. ii. Se elige la opción Todos los programas o Programas (Menú Inicio clásico) en el menú Inicio. iii. En el siguiente menú, se encontrará la opción MinGW Developer Studio, y se sitúa sobre ella el ratón. iv. Se elige la opción MinGW Developer Studio en el menú. -8- Programación Orientada a Objetos en C mediante MinGW Developer Studio. v. Transcurrido el tiempo de carga, se muestra el escritorio de MinGW Developer Studio. -9- Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 3 Crear una aplicación en lenguaje de programación C C - 10 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 3. Crear una aplicación en lenguaje de programación C. Inicialmente, el área de trabajo del entorno de desarrollo está vacía. Para crear ahora la estructura de una nueva aplicación, se procede del siguiente modo: a. Se elige la opción New en el menú File (o se pulsan las teclas Ctrl y N simultáneamente) o bien se pulsa el botón de la barra de herramientas. b. A continuación, se presenta una ventana en la que se puede elegir el tipo de aplicación que se desea crear. Se selecciona la pestaña Projects y la aplicación de tipo Win32 Console Application. Ahora se procede a nombrar el proyecto escribiendo el nombre que se desea en el cuadro Project name. En el cuadro Location se permite especificar la ruta de acceso al directorio, es decir, el directorio donde se creará la carpeta de nombre igual al del proyecto y que contendrá todos los ficheros relativos - 11 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. al proyecto (ejecutables, código fuente, etc.). Una vez especificado el nombre del proyecto y la ruta de acceso se confirma el cuadro de diálogo pulsando OK y ya se ha creado un proyecto nuevo. En el directorio especificado en el cuadro Location se habrá creado un fichero llamado nombre_del_proyecto.msp (MinGWStudio Project Files). Puede darse la situación de que el fichero creado tenga extensión *.mdsp en vez de *.msp. Esto se debe a que algunas versiones del compilador ponen dicha extensión a los ficheros de proyecto. c. El paso siguiente es crear un fichero y añadirlo al proyecto actualmente vacío. Se elige la opción New del menú File (o se pulsan las teclas Ctrl y N simultáneamente) o se pulsa el botón de la barra de herramientas. Se selecciona la pestaña Files y el fichero de tipo C/C++ Source File para crear un fichero de lenguaje de programación C (*.c) que contenga el código fuente. Se nombra el fichero (se debe añadir la extensión .c) en el cuadro File name y se confirma pulsando OK. El campo Location no debe ser modificado ya que por defecto se muestra la ruta de acceso al directorio del proyecto creado anteriormente. Además, la checkbox Add to project se encuentra activada para añadir el fichero al proyecto que se había creado previamente. Por tanto, la ruta de acceso y la checkbox no deben ser modificadas. En el directorio del proyecto se habrá creado un fichero llamado nombre_del_fichero.c (C Source File). - 12 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. d. El entorno ya está listo para introducir el código en la zona de edición. A continuación se describirá la estructura del entorno de desarrollo así como los componentes y sus propiedades más importantes. - 13 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 4 Estructura del entorno de desarrollo de MinGW Developer Studio - 14 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 4. Estructura del entorno de desarrollo de MinGW Developer Studio. A continuación se explicará la estructura del entorno de desarrollo en su pantalla inicial. Dicha pantalla consta de tres zonas principales y dos barras de tareas. 4.1. Zonas principales. Se distinguen tres zonas principales: la zona de workspace, la zona de edición y la zona de salida. 4.1.1. Zona de workspace. En esta zona aparecerá el nombre del proyecto que se cree así como los diferentes ficheros asociados a él. Los ficheros son agrupados en cuatro carpetas principales en función de su tipología. Estas carpetas son presentadas - 15 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. en estructura de árbol de tal forma que se pueden minimizar y maximizar para ocultar y ver su contenido respectivamente haciendo doble clic sobre ellas o sobre el símbolo situado a su izquierda. Las cuatro carpetas en las que son agrupados son: Source Files (Ficheros Fuente), Header Files (Ficheros de cabecera), Resource Files (Ficheros de recursos) y Other Files (Otros ficheros). Por ejemplo, en el proyecto del capítulo 3, la zona de workspace fue la siguiente: • Source Files: en esta carpeta aparece el fichero fuente asociado al proyecto. Este fichero puede tener las siguientes extensiones: *.c, *.cc, *.cpp, *.cxx. Se pueden añadir ficheros fuente a un proyecto ya creado pulsando la carpeta Source Files con el botón derecho del ratón y seleccionando Add source files to project… Se selecciona el fichero con la extensión apropiada y se añade al proyecto. - 16 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. • Header Files: en esta carpeta aparecen los ficheros de cabecera asociados al proyecto. Estos ficheros pueden tener las siguientes extensiones: *.h, *.hh, *.hpp, *.hxx. Se pueden añadir ficheros de cabecera a un proyecto ya creado pulsando la carpeta Header Files con el botón derecho del ratón y seleccionando Add header files to project… Se selecciona el fichero con la extensión apropiada y se añade al proyecto. - 17 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. • Resource Files: en esta carpeta aparecen los ficheros con extensión *.rc y *.rc2 asociados al proyecto. Estos ficheros son empleados por GTK+ (GIMP Tool Kit) para tratar las opciones predeterminadas de las aplicaciones. Con ellos se pueden cambiar los colores de cualquier control, poner un dibujo de fondo, etc. GTK+ es un grupo importante de bibliotecas o rutinas para desarrollar interfaces gráficas de usuario (GUI) mediante C, C++ y otros lenguajes de programación. Se pueden añadir ficheros *.rc y *.rc2 a un proyecto ya creado pulsando la carpeta Resource Files con el botón derecho del ratón y seleccionando Add resource files to project… Se selecciona el fichero con la extensión apropiada y se añade al proyecto. - 18 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. • Other Files: en esta carpeta aparecen ficheros de cualquier tipo distinto a los anteriormente citados que haya sido asociado al proyecto. Al igual que en las tres carpetas anteriores, se pueden añadir ficheros a un proyecto ya creado pulsando la carpeta Other Files con el botón derecho del ratón y seleccionando Add other files to project… Se selecciona el fichero con la extensión apropiada y se añade al proyecto. - 19 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Finalmente, en la zona de workspace es posible ejecutar acciones sobre el proyecto o sus ficheros asociados pulsando con el botón derecho del ratón sobre su icono correspondiente. De esta forma se evita tener que buscar en el menú principal la opción correspondiente al comportamiento que se desea realizar. Sobre un proyecto aparecen las siguientes opciones: o Close: mismo comportamiento que File Close. o Set Active Configuration: mismo comportamiento que Build Set Active Configuration. o Settings: mismo comportamiento que Project Settings. o Build: mismo comportamiento que Build Build. o Rebuild: mismo comportamiento que Build Rebuild. o Build All Configurations: mismo comportamiento que Build Build All Configurations. o Clean: mismo comportamiento que Build Clean. o Clean All Configurations: mismo comportamiento que Build Clean All Configurations. o Execute: mismo comportamiento que Build Execute. o Export Makefile: mismo comportamiento que Project Export Makefile. - 20 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Los comportamientos correspondientes a cada opción serán explicados en detalle en el apartado 4.2.1 ‘Menú principal’. Por otra parte, si se pulsa con el botón derecho un fichero asociado a un determinado proyecto aparecen las siguientes opciones: o Open nombre_fichero: abre el fichero seleccionado en la zona de edición. o Compile nombre_fichero: compila el fichero seleccionado. o Remove nombre_fichero from project: elimina el fichero seleccionado del proyecto. La opción Compile nombre_fichero sólo aparece en los ficheros Source Files y en los ficheros Header Files mientras que las otras dos opciones son comunes a los cuatro tipos de ficheros que pueden asociarse a un proyecto. 4.1.2. Zona de edición. En esta zona se podrá editar el código asociado al proyecto. Dicho código es presentado al usuario en diferentes colores para permitir diferenciar segmentos de código en función de su tipología. El color verde es empleado para destacar los comentarios y observaciones que se escriban en el código mientras que el color azul se utiliza para destacar palabras clave del lenguaje de programación tales como tipos de variables (int, char, float, …), operadores (‘==’, ‘&’, ‘*’, …), palabras reservadas (‘do’, ‘if’, ‘for’, ‘return’, …), etc. Por otra parte, las directivas del precompilador (include, define, …) se muestran en color marrón mientras que el texto a presentar con printf y el tipo de variable a leer con scanf se muestran en color púrpura. Finalmente, los nombres de variables y las funciones propias del lenguaje como printf, scanf, gets, fflush, stdin, etc. se muestran en color negro. A continuación se muestra un ejemplo de código fuente donde se observan los diferentes colores en la zona de edición según la tipología del código. - 21 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. En el ejemplo anterior también se puede observar que el compilador presenta en el lado izquierdo de la zona de edición la numeración de las líneas del código. De esta forma se facilita el seguimiento del código y la futura estimación de la complejidad del programa. Además, se ofrece la posibilidad de ocultar bloques de código independientes como declaraciones de estructuras, funciones, bloques if-else, bloques while o do-while, bloques for o incluso la propia función principal (main). De esta forma se optimiza la búsqueda de errores en código permitiendo al usuario ocultar bloques de código en los que se descarta la aparición de fallos. También hay que destacar que existe una manera de ampliar la zona de edición para facilitar la visualización del código o en caso de que el usuario tenga problemas de vista. Esta forma de hacer zoom sobre la zona de edición consiste en situarse sobre la misma y pulsar la tecla Ctrl y girar la rueda del ratón hacia atrás simultáneamente. Si, por el contrario, se pulsa la tecla Ctrl y se gira la rueda del ratón hacia delante simultáneamente entonces se disminuirá el zoom sobre la zona de edición. De esta manera tan sencilla se permite al usuario ajustar el área de visión de la zona de edición en función de sus necesidades. - 22 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Por último, cuando se abre un fichero aparece una pestaña con su nombre en la parte superior de la zona de edición. Si se pulsa con el botón derecho sobre dicha pestaña aparecen una serie de opciones que permiten ejecutar acciones sobre el fichero sin necesidad de buscar la opción en el menú principal. Estas opciones son las siguientes: o Close: mismo comportamiento que File Close. o Save: mismo comportamiento que File Save. o Save As: mismo comportamiento que File Save As. o Find: mismo comportamiento que Edit Find. o Replace: mismo comportamiento que Edit Replace. o Print: mismo comportamiento que File Print. o Print Preview: mismo comportamiento que File Print Preview. Los comportamientos correspondientes a cada opción serán explicados en detalle en el apartado 4.2.1 ‘Menú principal’. 4.1.3. Zona de salida. En esta zona se mostrarán mensajes acerca de las operaciones efectuadas por el compilador a la hora de compilar, enlazar y ejecutar un programa. Así mismo, se mostrará información acerca de los errores y warnings (advertencias) que se produzcan al efectuar alguna de las operaciones anteriormente comentadas. Estos mensajes serán presentados en la pestaña Build, primera de las tres pestañas de las que consta la zona de salida. La segunda pestaña (Debug) presenta información acerca de las operaciones del depurador de errores si bien el funcionamiento del mismo se verá en el capítulo 5 ‘Depuración de programas’. La tercera y última pestaña (Find in Files) se encarga de presentar los resultados de la búsqueda en ficheros, es decir, la información relativa a la búsqueda de palabras en ficheros del proyecto. La búsqueda en ficheros será explicada con mayor detalle en el apartado 4.2.1 ‘Menú principal’. A continuación se explicará en detalle la pestaña Build donde - 23 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. se muestran mensajes relativos a la compilación, enlazado y ejecución de programas. Bajo estas líneas se muestra un ejemplo de un programa que, tras ser compilado, presenta errores y warnings: Como se puede observar, el programa presenta tres errores y un warning. Las dos primeras líneas de la zona de salida muestran un mensaje donde se informa de que el proyecto de nombre Proyecto ha sido compilado. La segunda línea (Compiling…) es generada antes de llevarse a cabo la compilación y presenta información acerca de su resultado. La tercera línea indica el nombre del fichero compilado (programa.c) mientras que la cuarta línea indica el nombre de la función donde se han producido los errores y warnings (main). Las cuatro líneas siguientes (tantas como errores y warnings se han producido) muestran información acerca de cada uno de los errores y warnings. Por cada fallo se presenta la siguiente información: fichero en el que se ha producido el fallo, número de línea dentro del fichero en el que se ha producido el fallo, tipo de fallo (error o warning) y breve descripción del fallo producido. Hay que destacar que el warning que se muestra en el ejemplo es característico de MinGW Developer Studio ya que se debe introducir una línea en blanco al final del código fuente. En caso contrario, el compilador presentará una advertencia que, si bien no - 24 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. afecta a la ejecución del programa, resulta molesto para el usuario. Finalmente, la última línea muestra un resumen del resultado de la compilación en el que se muestra el número total de errores y warnings que se han producido tras la compilación. Además, a la izquierda de esta información aparece el nombre de un fichero: programa.o. Este fichero es generado por el compilador al hacer la compilación y aparece en la carpeta Debug del directorio del proyecto que ha sido compilado. Una de las características que presenta el compilador en la zona de salida es la facilidad a la hora de localizar de forma rápida y precisa errores y warnings en código. Aunque el compilador informa acerca del número de línea en que se producen los errores y warnings tal y como se ha comentado anteriormente, la forma más fácil y rápida de localizar dichos fallos es haciendo doble clic sobre la línea de la zona de salida en la que se informa acerca del fallo. Una vez hecho esto, la línea correspondiente al fallo se sombreará en color amarillo y en la zona de edición se mostrará el segmento de código en el que se produjo el fallo. Dentro de este segmento faltaría localizar la línea en la que se produjo el fallo. Pues bien, esto se realiza por medio de una flecha de color verde situada en el margen izquierdo de la zona de edición. Esta flecha está situada a la derecha del número de línea en que se produjo el fallo y apunta a la línea que lo contiene. De esta forma el fallo ya ha sido localizado y se puede corregir de forma rápida sin necesidad de realizar una búsqueda en la zona de edición para encontrar la línea en que se produjo. La situación anteriormente descrita se ilustra en la siguiente captura: - 25 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Si en vez de realizar la compilación del programa se hiciera el enlazado del mismo, se presentarían las siguientes diferencias: • La segunda línea mostraría el mensaje ‘Compiling source file(s)…’ en vez de ‘Compiling…’ ya que llevaría a cabo la compilación y enlazado de todos los ficheros fuente asociados al proyecto. En la compilación, únicamente se compila un fichero. Si el enlazado es satisfactorio se muestra el mensaje ‘Linking…’ antes de mostrar el resultado del enlazado sin fallos. Si por el contrario el enlazado tiene fallos, se muestran los fallos al igual que en la compilación. • La última línea muestra el nombre del fichero programa.exe que se genera al hacer el enlazado y que aparece en la carpeta Debug del directorio del proyecto que ha sido compilado. Este fichero sustituye al fichero programa.o que había sido generado en la compilación dado que al realizar el enlazado también se hace la compilación. Si se realizara la ejecución del programa, la zona de salida contendría información relativa al enlazado puesto que éste es imprescindible para ejecutar - 26 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. el programa. Si se intenta ejecutar el programa sin llevar a cabo el enlazado se presenta el siguiente cuadro de diálogo: El cuadro de diálogo sobre estas líneas informa al usuario que el fichero ha sido modificado desde el último enlazado o compilación o bien no ha sido enlazado todavía. Si se pulsa ‘Sí’ el compilador llevará a cabo el enlazado (incluye la compilación) del programa y su ejecución. Si, por el contrario, se pulsa ‘No’ se llevará a cabo la ejecución del programa con la última versión enlazada del fichero (el fichero *.exe en la carpeta Debug del directorio del proyecto) y, por tanto, se estará ejecutando un código distinto al que hay en la zona de edición. Si se hubiera pulsado ‘Cancelar’ el cuadro de diálogo simplemente habría desaparecido. 4.2. Barras de tareas. Además de las zonas principales explicadas anteriormente, existen dos barras de tareas en la parte superior de la pantalla que permiten manejar las diversas opciones del programa, realizar ajustes y ejecutar de forma directa las operaciones más comunes por medio de iconos. Estas dos barras de tareas son: el menú principal y la barra de herramientas. 4.2.1. Menú principal. Consta de nueve menús que permiten al usuario llevar a cabo operaciones tales como el guardado del proyecto, la creación de un nuevo proyecto, ajustar las opciones del compilador, etc. Estos menús son: File (Archivo), Edit (Editar), View (Vista), Project (Proyecto), Build (Construir), Debug (Depurar), Tools (Herramientas), Window (Ventana) y Help (Ayuda). Cada uno de los menús será explicado con mayor detalle a continuación. - 27 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. File: Consta de catorce opciones como son New (Nuevo), Open (Abrir), Close (Cerrar), Close All (Cerrar todo), Save (Guardar), Save As (Guardar como), Save All (Guardar todo), Export (Exportar), Page Setup (Configurar página), Print (Imprimir), Print Preview (Vista previa de impresión), Recent Files (Ficheros recientes), Recent Projects (Proyectos recientes) y Exit (Salir). o New: Puede activarse también pulsando simultáneamente las teclas Ctrl y N. Esta opción permite crear un nuevo proyecto tal y como se ha explicado en el capítulo 3 si bien solo se explicó cómo crear un proyecto de aplicación de consola Win32. Hay que recordar que los programas de consola se desarrollan mediante Funciones de consola, las cuales proporcionan compatibilidad con el modo de caracteres en ventana de consola. Las bibliotecas en tiempo de ejecución del compilador MinGW Developer Studio también proporcionan entrada y salida de ventanas de consola con funciones estándar de E/S, como printf() y scanf(). Las aplicaciones de consola no tienen interfaz gráfica de usuario. Al compilarse producen un fichero .exe que se puede ejecutar como una aplicación independiente desde la línea de comandos. Otro tipo de proyecto que se puede crear es el de aplicación Win32. Una aplicación Win32 es un programa ejecutable (EXE) escrito en C o C++, que utiliza llamadas a la API Win32 para crear una interfaz gráfica de usuario. El tercer tipo de proyecto que se permite crear es el de biblioteca de vínculos dinámicos (DLL) Win32. Un fichero DLL para Win32 es un fichero binario, escrito en C o C++, que utiliza llamadas a la API Win32 en lugar de llamadas a clases - 28 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. MFC (Microsoft Foundation Classes) y que actúa como una biblioteca compartida de funciones que pueden utilizar simultáneamente múltiples aplicaciones. El cuarto tipo de proyecto que se permite crear es el de biblioteca estática. Una biblioteca estática, también conocida como fichero, consiste en un conjunto de rutinas que son copiadas en una aplicación por el compilador o el enlazador, produciendo ficheros con código objeto y un fichero ejecutable independiente. Este proceso, y el fichero ejecutable, se conocen como construcción estática de la aplicación objetivo. La dirección real, las referencias para saltos y otras llamadas a rutinas se almacenan en una dirección relativa o simbólica, que no puede resolverse hasta que todo el código y las bibliotecas son asignados a direcciones estáticas finales. Otro tipo de proyecto que se puede crear es el de aplicación GTK+. Una aplicación GTK+ es un programa escrito en lenguaje de programación C que realiza llamadas a bibliotecas o rutinas GTK (GIMP Toolkit) para desarrollar interfaces gráficas de usuario (GUI). La gran ventaja de GTK+ es que es multiplataforma por lo que se pueden escribir programas en plataforma Windows y que éstos sean portables a plataforma Linux, por ejemplo. Además, GTK+ es software libre (bajo la licencia LGPL) y parte importante del proyecto GNU, que tiene por objetivo la creación de un sistema operativo completamente libre: el sistema GNU. El último tipo de proyecto que se puede crear es el de aplicación wxWindows (actualmente wxWidgets). Una aplicación wxWindows es un programa escrito en lenguaje de programación C++ que realiza llamadas a bibliotecas o rutinas wxWindows (wxWidgets) para desarrollar interfaces gráficas de usuario (GUI). Al igual que GTK+, wxWindows también es multiplataforma y - 29 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. software libre (bajo la licencia LGPL). Hay que resaltar que el compilador MinGW Developer Studio fue publicado en el año 2002, un año antes de que Microsoft interpusiera una demanda contra wxWindows por una posible confusión con el nombre de su sistema operativo. Desde entonces, wxWindows recibe el nombre de wxWidgets. Las wxWidgets proporcionan una interfaz gráfica basada en las bibliotecas ya existentes en el sistema (nativas), con lo que se integran de forma óptima y resultan muy portables entre distintos sistemas operativos. El 22 de Abril de 2005 fue incluida la versión 2.6 de wxWidgets en la versión 2.05 de MinGW Developer Studio. Además de los tipos de proyecto citados anteriormente existen cuatro tipos de ficheros que se pueden crear mediante MinGW Developer Studio: C/C++ Source File (fichero fuente C/C++), C/C++ Header File (fichero de cabecera C/C++), Resource Script (script de recurso) y Text File (fichero de texto). El fichero C/C++ Source File es un fichero que contiene el código fuente del programa escrito en lenguaje de programación C o C++ y que aparecerá en la carpeta Source Files de la zona de workspace. Este fichero puede tener extensión *.c, *.cc, *.cpp o *.cxx. El fichero C/C++ Header File, sin embargo, es un fichero, a menudo en código fuente, que es incluido automáticamente en otro fichero fuente (source file) por parte del compilador. Típicamente, los ficheros de cabecera son incluidos en otro fichero fuente por medio de directivas del compilador al comienzo (o cabecera) de éste. Un fichero de cabecera contiene normalmente declaraciones de subrutinas (funciones), variables y otros identificadores. Los identificadores que necesitan ser declarados en más de un fichero fuente pueden declararse en un fichero de cabecera que será incluido posteriormente cuando su contenido sea requerido. Este - 30 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. fichero aparecerá en la carpeta Header Files de la zona de workspace y tendrá extensión *.h, *.hh, *.hpp o *.hxx. Por otra parte, el fichero Resource Script contiene declaraciones que definen todos los elementos que serán incluidos en el fichero binario de recursos compilado (compiled binary resource file). Cada declaración describe un elemento de recurso (resource item), identificado por un ID, y parámetros adicionales (que varían en función del tipo de recurso). Un resource script puede incluso referenciar un resource item que esté almacenado en un fichero independiente, como un bitmap o un icono. Este fichero aparecerá en la carpeta Resource Files de la zona de workspace y tendrá extensión *.rc o *.rc2. Por último, el fichero Text File contiene comentarios, información administrativa (versión, desarrollador/es, fecha, etc.) y cualquier otra información que se quiera adjuntar al proyecto. Este fichero aparecerá en la carpeta Other Files de la zona de workspace y tendrá extensión *.txt. o Open: Puede activarse también pulsando simultáneamente las teclas Ctrl y O. Esta opción permite abrir un fichero de los siguientes tipos: C/C++ Files –incluye Source Files, Header Files y Resource Files– (extensiones *.c, *.cc, *.cpp, *.cxx, *.h, *.hh, *.hpp, *.hxx, *.rc y *.rc2), Text Files (extensión *.txt), MinGWStudio Project Files (extensión *.msp o *.mdsp) y cualquier otro fichero con extensión válida para ser abierta por el software. A continuación se muestra una captura de la ventana que aparece al pulsar la opción Open y que permite seleccionar el fichero a abrir. - 31 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Close: Esta opción cierra el fichero que se encuentre activo en la zona de edición. Es decir, de entre todos los ficheros que pueden encontrarse abiertos simultáneamente en la zona de edición y que se visualizan por medio de pestañas en la parte superior cierra el fichero que se esté visualizando. La opción Close se encontrará desactivada si no hay ningún fichero abierto en la zona de edición. o Close All: Esta opción cierra todos los ficheros que se encuentren abiertos simultáneamente y que se visualizan por medio de pestañas en la parte superior de la zona de edición. La opción Close All se encontrará desactivada si no hay ningún fichero abierto en la zona de edición. o Save: Puede activarse también pulsando simultáneamente las teclas Ctrl y S. Esta opción guarda los cambios efectuados en el fichero que se encuentre activo en la zona de edición. El fichero modificado es guardado en el directorio del proyecto donde se encuentra ubicado si bien la opción Save As que se verá a continuación permite guardarlo en otra ubicación diferente. La opción Save se encontrará desactivada si no se ha realizado cambio alguno en el fichero desde su último guardado o bien si no hay ningún fichero abierto en la zona de edición. - 32 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Save As: Esta opción guarda los cambios efectuados en el fichero que se encuentre activo en la zona de edición en una ubicación que se debe especificar. Esta opción permite, por tanto, guardar el fichero en otra ubicación diferente a la del directorio del proyecto así como renombrarlo. Una vez pulsada esta opción se muestra un cuadro de diálogo en el que se solicita la confirmación del guardado. Si se pulsa ‘Sí’ (en cualquier otro caso se renuncia a guardar los cambios) aparecerá entonces un segundo cuadro de diálogo en el que se puede especificar el directorio en el que se quiere guardar el fichero, la extensión que se le quiere dar y el nombre. La opción Save As se encontrará desactivada si no hay ningún fichero abierto en la zona de edición. A continuación se muestran los cuadros de diálogo que aparecen al pulsar sobre esta opción e intentar guardar un fichero de cabecera. - 33 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Save All: Esta opción guarda todos los cambios efectuados en los ficheros que se encuentren abiertos y que aparezcan en las pestañas en la parte superior de la zona de edición. La opción Save All se encontrará desactivada si no se ha realizado cambio alguno en los ficheros abiertos desde la última vez que se produjo el guardado de los mismos o bien si no hay ningún fichero abierto en la zona de edición. Si alguno de ellos ha sido modificado, entonces la opción Save All llevará a cabo el guardado de todos ellos a pesar de que algunos no habían sido modificados. La única condición, por tanto, para que la opción se encuentre activa es que al menos uno de los ficheros abiertos haya sufrido cambios desde la última vez que se produjo su guardado. En tal caso el resultado de esta opción será el mismo que con la opción Save. o Export (to HTML): Esta opción permite pasar a formato HTML (HyperText Markup Language) el fichero que se muestre en la zona de edición y cuyo nombre se visualizará en la pestaña activa en la parte superior de dicha zona. Esta función es de gran utilidad dado que HTML es el lenguaje de marcado predominante para la construcción de páginas Web. Es usado para describir la estructura y el contenido en forma de texto, así como para complementar el texto con objetos tales como imágenes. Además de permitir la conversión a formato HTML también permite especificar la ubicación donde se quiere guardar el fichero ya convertido. La opción Export se encontrará desactivada si no hay ningún fichero abierto en la zona de edición. A continuación se muestra una captura del cuadro de diálogo que permite la conversión a formato HTML así como del fichero HTML resultante. - 34 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Page Setup: Esta opción permite configurar las opciones de página para la impresión y está muy relacionada con la opción Print que se explicará en el siguiente punto. Esta opción permite ajustar el papel a utilizar (tamaño y origen), la orientación (vertical u horizontal) y los márgenes de página (izquierdo, derecho, superior e inferior). Además, permite seleccionar la impresora a utilizar para la impresión y ajustar sus propiedades pulsando el botón ‘Impresora…’. Por último, se permite - 35 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. seleccionar para la impresión una impresora de la red (por defecto Red de Microsoft Windows) pulsando el botón ‘Red…’ dentro del cuadro que aparece al pulsar ‘Impresora…’. La opción Page Setup se encontrará desactivada si no hay ningún fichero abierto en la zona de edición. A continuación se muestran los cuadros que aparecen al pulsar la opción Page Setup, al pulsar el botón ‘Impresora…’ y al pulsar el botón ‘Red…’. - 36 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Print: Puede activarse también pulsando simultáneamente las teclas Ctrl y P. Esta opción permite imprimir el fichero que aparece en la zona de edición. Al pulsarla aparece el cuadro de impresión de Microsoft Windows donde se pueden especificar aspectos como el número de copias a imprimir, las preferencias de impresión, el intervalo de páginas a imprimir, etc. La opción Print se encontrará desactivada si no hay ningún fichero abierto en la zona de edición. A continuación se muestra el cuadro de impresión que aparece al pulsar esta opción. o Print Preview: Esta opción permite la previsualización de página antes de su impresión. Al pulsarla aparece una nueva ventana titulada ‘MinGWStudio Preview’ que permite visualizar el documento que se imprimiría en caso de pulsar la opción Print. Además, esta ventana permite invocar a la opción Print directamente por medio del botón Print situado en la parte superior de forma que no hay que cerrar la ventana y pulsar la opción desde el menú File. El botón Close cierra la ventana de previsualización mientras que los cuatro botones de dirección permiten (de izquierda a derecha) ir a la primera página, retroceder, avanzar e ir a la última página respectivamente. Por último, la combo box situada en la parte derecha permite ajustar el zoom de visualización de página (desde - 37 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 10% hasta 200%). La opción Print Preview se encontrará desactivada si no hay ningún fichero abierto en la zona de edición. A continuación se muestra una captura de la ventana ‘MinGWStudio Preview’ que aparece al pulsar la opción Print Preview. o Recent Files: Esta opción muestra los ficheros que han sido abiertos más recientemente de forma que se facilita su rápida apertura sin necesidad de buscarlos en el directorio y abrirlos con la opción Open. Los ficheros se muestran ordenados por orden de visualización (el más reciente será el número 1 y el más antiguo será el último número). El máximo número de ficheros recientes que mostrará esta opción es nueve. El fichero más reciente será denotado por el nombre y su extensión mientras que los ficheros restantes mostrarán también su ruta de acceso. A continuación se muestra una captura de la opción Recent Files. - 38 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Recent Projects: Esta opción presenta la misma funcionalidad que la opción Recent Files en el punto anterior si bien esta opción se refiere a proyectos en vez de a ficheros. Permite, por tanto, ver los proyectos que han sido abiertos más recientemente. La única diferencia que presenta respecto de la opción Recent Files es que en este caso todos los proyectos recientes muestran la ruta de acceso además del nombre del proyecto con su correspondiente extensión (*.msp o *.mdsp). A continuación se muestra una captura de la opción Recent Projects. o Exit: Puede activarse también pulsando simultáneamente las teclas Alt y X. Esta opción cierra la aplicación. En el caso de que exista un proyecto abierto y alguno o varios de sus ficheros presenten cambios entonces la aplicación preguntará si se desean guardar cada uno de los ficheros que han sido modificados. A continuación se muestra una captura del cuadro que presenta la aplicación en caso de que un fichero presente cambios. - 39 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Edit: Consta de dieciséis opciones como son Undo (Deshacer), Redo (Rehacer), Cut (Cortar), Copy (Copiar), Paste (Pegar), Select All (Seleccionar todo), Find (Buscar), Find Next (Buscar siguiente), Find Previous (Buscar anterior), Find in Files (Buscar en ficheros), Replace (Reemplazar), Match Brace (Encontrar llave), Go To (Ir a), Advanced (Avanzado), File Format (Formato de fichero) y Options (Opciones). o Undo: Puede activarse también pulsando simultáneamente las teclas Ctrl y Z. Esta opción permite deshacer todos los pasos dados desde la última vez que se guardó el fichero. Esta opción se encuentra desactivada si no hay ningún proyecto abierto o si hay un proyecto abierto y ninguno de sus ficheros ha sido modificado. o Redo: Puede activarse también pulsando simultáneamente las teclas Ctrl e Y. Esta opción permite rehacer la última acción realizada así como acciones que se han deshecho por medio de la opción Undo explicada anteriormente. Esta opción se encuentra desactivada si no hay ningún proyecto abierto o si hay un proyecto abierto y ninguno de sus ficheros ha sido modificado y luego se ha pulsado la opción Undo. o Cut: Puede activarse también pulsando simultáneamente las teclas Ctrl y X. Esta opción se aplica sobre trozos de código o texto, ahorrando gran trabajo cuando se quieren desplazar dichos trozos de un lugar a otro. El primer paso a la hora de cortar un texto es seleccionarlo para indicarle al programa sobre qué texto se quiere ejecutar la acción. Cuando se aplica esta opción sobre un texto, éste desaparece del lugar de origen. Para depositarlo en otro sitio se utiliza la opción Paste que se explicará posteriormente. Una vez que un texto se ha cortado permanece en la memoria mientras no se copie o corte otra cosa. Esta opción se encuentra desactivada si no hay ningún proyecto abierto o si hay un proyecto abierto y no ha sido seleccionado texto alguno. - 40 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Copy: Puede activarse también pulsando simultáneamente las teclas Ctrl y C. Esta opción, al igual que la anterior, se aplica sobre trozos de código o texto y permite repetir sentencias de código, bucles, etc. Al igual que en el caso anterior, el primer paso es seleccionar el texto a copiar. El texto copiado no desaparece del lugar de origen, pero el ordenador ha creado una copia de él. Para depositarlo en otro sitio se utiliza la opción Paste que se explicará posteriormente. Una vez que un texto se ha copiado permanece en la memoria mientras no se copie o corte otra cosa. Así, si se necesita volver a pegar ese mismo texto no hace falta volver a copiar. Esta opción se encuentra desactivada si no hay ningún proyecto abierto o si hay un proyecto abierto y no ha sido seleccionado texto alguno. o Paste: Puede activarse también pulsando simultáneamente las teclas Ctrl y V. Esta opción permite pegar el texto copiado o cortado y del cual el ordenador ha creado una copia que permanece en la memoria mientras no se copie o corte otra cosa. Esta opción se encuentra desactivada si no hay ningún proyecto abierto o si hay un proyecto abierto y no ha sido copiado o cortado texto alguno. o Select All: Puede activarse también pulsando simultáneamente las teclas Ctrl y A. Esta opción permite seleccionar todo el texto del fichero que se encuentre abierto en la zona de edición. Esta opción se encuentra desactivada si no hay ningún fichero en la zona de edición. o Find: Puede activarse también pulsando simultáneamente las teclas Ctrl y F. Esta opción permite buscar palabras y frases en el fichero que se encuentre abierto en la zona de edición. A continuación se muestra una captura del cuadro que aparece al pulsar sobre esta opción y que ayudará en la explicación. - 41 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. En el cuadro de texto Find what hay que escribir la palabra o frase a buscar. La caja Direction permite seleccionar si la búsqueda a realizar va a ser de abajo a arriba desde la posición actual (seleccionada opción Up) o de arriba abajo (seleccionada opción Down) en el texto. La checkbox Match whole word only permite especificar que solo se presenten los resultados de palabras que coincidan exactamente con la palabra a buscar y que no esté contenida o sea parte de otra. La checkbox Match case permite presentar resultados independientemente de si éstos están en mayúsculas o en minúsculas. Por último, la checkbox Wrap around, que por defecto se encuentra activada, permite reanudar la búsqueda desde el principio una vez que ésta ha llegado al final. Actúa, por tanto, de forma circular. Una vez que se ha introducido la palabra o frase a buscar y se han activado las opciones que interesen se pulsa el botón Find Next que sombreará en el propio texto de la zona de edición el resultado de la búsqueda (match). Si el resultado no es el que se buscaba se pulsará de nuevo el botón Find Next para reanudarla y así sucesivamente hasta encontrar el resultado esperado. La opción Find se encuentra desactivada si no hay ningún fichero en la zona de edición. o Find Next: Puede activarse también pulsando la tecla F3. Esta opción permite ver el siguiente resultado de la búsqueda efectuada con la opción Find. Su funcionamiento es igual al del botón Find Next que aparece en el cuadro de búsqueda de la opción Find explicado anteriormente. En caso de que se pulse sobre la opción Find Next sin haber iniciado una búsqueda se ejecutará la opción Find. La opción Find Next se encuentra desactivada si no hay ningún fichero en la zona de edición. - 42 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Find Previous: Puede activarse también pulsando simultáneamente las teclas Shift y F3. Esta opción permite ver el resultado anterior de la búsqueda efectuada con la opción Find. Su funcionamiento es igual al de la opción Find Next con la diferencia de que se muestra el resultado anterior en vez del resultado siguiente. En caso de que se pulse sobre la opción Find Previous sin haber iniciado una búsqueda se ejecutará la opción Find. La opción Find Previous se encuentra desactivada si no hay ningún fichero en la zona de edición. o Find in Files: Esta opción permite buscar palabras o frases en ficheros con extensiones soportadas por MinGW Developer Studio y que se encuentren en cualquier directorio. Para ello se muestra un cuadro de búsqueda que permite especificar la palabra o frase a buscar, la extensión de los ficheros en los que se quiere buscar (*.c, *.cc, *.cpp, *.cxx, *.h, *.hh, *.hpp, *.hxx, *.rc, *.rc2, *.def, *.htm, *.html, *.txt, *.*) y el directorio en el que se quiere buscar. Además, muestra tres checkboxes que permiten especificar propiedades de búsqueda. Las checkboxes Match whole Word only y Match case ya han sido explicadas en la opción Find y sus funciones son las mismas. La checkbox Look in subfolders está activada por defecto y permite realizar la búsqueda en subcarpetas del directorio especificado en la pestaña In folder. El resultado de la búsqueda será mostrado en la pestaña Find in Files de la zona de salida. A continuación se muestra una captura del cuadro de búsqueda de la opción Find in Files. - 43 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Replace: Puede activarse también pulsando simultáneamente las teclas Ctrl y H. Esta opción permite reemplazar una palabra o frase por otra que se debe especificar. La palabra o frase a reemplazar se escribe en el cuadro de texto Find what mientras que la palabra o frase que la reemplace se escribe en el cuadro Replace with. Las tres checkboxes y sus funciones ya han sido explicadas en la opción Find mientras que el cuadro Replace in permite realizar el reemplazo en todo el fichero (opción Whole file, que está activada por defecto) o solo en una parte de él que debe ser seleccionada (opción Selection). El botón Find Next ya ha sido explicado anteriormente, mientras que el botón Replace ejecuta un único reemplazo frente a Replace All que reemplaza todos los resultados de la búsqueda simultáneamente. La opción Replace se encuentra desactivada si no hay ningún fichero en la zona de edición. o Match Brace: Puede activarse también pulsando simultáneamente las teclas Ctrl y B. Esta opción permite localizar la llave inicial ({) o final (}) de un bloque de código. Esto es especialmente útil en programas con un gran número de líneas de código para localizar el comienzo o el fin de funciones, bucles (for, while, do-while), bloques if-else, switch, etc. Para localizar el inicio/fin de un bloque de código hay que situarse en la llave final (})/inicial ({) y ejecutar la opción. La opción Match brace se encuentra desactivada si no hay ningún fichero en la zona de edición. - 44 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Go To: Puede activarse también pulsando simultáneamente las teclas Ctrl y G. Esta opción permite ir directamente a una línea de código determinada que se debe especificar en un cuadro de diálogo que aparece al ejecutar la opción. La opción Go to se encuentra desactivada si no hay ningún fichero en la zona de edición. A continuación se muestra una captura del cuadro que aparece al ejecutar la opción Go to. o Advanced: Esta opción permite realizar cuatro acciones diferentes sobre un fragmento de código que se debe seleccionar. La primera opción se llama Make Selection C style comment y convierte el fragmento seleccionado a estilo de comentario en lenguaje de programación C, es decir, el fragmento precedido de ‘/*’ y con ‘*/’ al final. Esta opción también puede ejecutarse pulsando simultáneamente las teclas Ctrl e Insert. La segunda opción se llama Make Selection C++ style comment y convierte el fragmento seleccionado a estilo de comentario en lenguaje de programación C++, es decir, el fragmento con ‘//’ en cada línea. Esta opción también puede ejecutarse pulsando simultáneamente las teclas Ctrl, Shift e Insert. La tercera opción se llama Make Selection Uppercase y convierte el fragmento seleccionado a mayúsculas. Esta opción también puede ejecutarse pulsando simultáneamente las teclas Ctrl, Shift y U. La última opción se llama Make Selection Lowercase y convierte el fragmento seleccionado a minúsculas. Esta opción también puede ejecutarse pulsando simultáneamente las teclas Ctrl y U. La opción Advanced se encuentra desactivada si no hay ningún fichero en la zona de edición. A continuación se muestra una captura de las acciones posibles de la opción Advanced. - 45 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o File Format: Esta opción permite codificar el fichero que se encuentre en la zona de edición de tal forma que sea portable a Windows, UNIX y Macintosh por medio de tres opciones específicas: Windows (CR/LF), UNIX (LF) y Macintosh (CR). Al editar ficheros en MinGW Developer Studio y guardarlos, las líneas se terminan con la combinación de caracteres “CR/LF”, que significan retorno de carro/avance o fin de línea. Esto se produce en sistemas Windows mientras que en sistemas UNIX se terminan sólo con avance de línea. En sistemas Macintosh, por otro lado, terminan sólo con retorno de carro. Esta opción, por tanto, favorece la portabilidad de ficheros entre los tres tipos de sistemas más utilizados. La opción File Format se encuentra desactivada si no hay ningún fichero en la zona de edición. o Options: Esta opción permite modificar una serie de parámetros agrupados en ocho categorías: Project (Proyecto), Editor (Editor), Tabs (Tabulaciones), Compiler (Compilador), Build (Construir), Directories (Directorios), Help (Ayuda) y Format (Formato). La categoría Project permite cargar el último proyecto abierto cuando se inicia el programa y cargar los documentos asociados a un proyecto cuando éste se abre. - 46 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. La categoría Editor permite modificar opciones de guardado de ficheros, opciones de autocompletado, opciones de pestañas en la visualización de ficheros y opciones de impresión. La categoría Tabs permite modificar parámetros relativos a las tabulaciones del texto de la zona de edición. Se puede modificar el espaciado, el sangrado, insertar espacios, mantener tabulaciones, realizar un sangrado automático, etc. La categoría Compiler permite especificar el directorio que utiliza el programa (MinGW path) y donde se encuentran los ficheros de librería (carpeta lib), los ficheros de include (carpeta include), los ficheros de recursos (carpeta include), etc. La categoría Build permite guardar un fichero automáticamente antes de ser compilado y ejecutado cuando se pulsa la opción Build. Además, permite escribir siempre las dependencias cuando se escribe un fichero Makefile. Este fichero se compone de un conjunto de dependencias y reglas. Una dependencia tiene un fichero objetivo (target), que es el fichero a crear, y un conjunto de ficheros fuente de los cuales depende el fichero objetivo. Una regla describe cómo crear el fichero objetivo a partir de los ficheros de los que éste depende. La categoría Directories muestra los directorios donde se encuentran los ficheros de include (Include files), los ficheros de librería (Library files) y los ficheros de recursos (Resource files). Además, permite modificar estos directorios mediante una serie de botones que permiten eliminar el directorio actual y buscar manualmente el directorio nuevo. La categoría Help muestra los directorios donde se encuentran los ficheros de ayuda de win32 y de wxWindows así como modificar dichos - 47 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. directorios. Además, permite especificar que las sugerencias (Call tips) se muestren según el estándar ANSI C y la API de Windows (WinAPI). La categoría Format permite modificar opciones de estilo de texto en la zona de edición y en la zona de salida. Se permite modificar el tamaño del texto, la fuente, el color (del texto, del fondo, del sombreado de errores,…) y el estilo de fuente (negrita, cursiva y subrayado). Estos cambios pueden visualizarse en el propio cuadro de opciones gracias a la ventana Sample que muestra el resultado de los cambios en caso de que éstos se lleven a cabo. A continuación se muestra una captura del cuadro Options en la categoría Format. - 48 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. View: Consta de once opciones como son Toolbar (Barra de herramientas), Status Bar (Barra de estado), Toggle Current Fold (Ocultar bloque actual), Toggle All Folds (Ocultar todos los bloques), End Of Line (Fin de Línea), Line Numbers (Números de Línea), Indentation Guides (Guías de sangrado), Margin (Margen), Fold Margin (Margen de bloque), Project Window (Ventana de Proyecto) y Output Window (Ventana de Salida). o Toolbar: Esta opción permite mostrar (opción activada) o esconder (opción desactivada) la barra de herramientas, que se explicará en el apartado 4.2.2 ‘Barra de herramientas’. o Status Bar: Esta opción permite mostrar (opción activada) o esconder (opción desactivada) la barra de estado. Esta barra está situada debajo de la zona de salida y está dividida en dos zonas diferenciadas. Una zona muy amplia situada en el lado izquierdo muestra información acerca de la acción que realiza cada una de las opciones de los menús cuando el cursor se encuentra situado sobre cada opción. La segunda zona está situada en el lado derecho y muestra el número de línea y columna en el que se encuentra el cursor en la zona de edición así como el modo de teclado activo (INS/OVR) (inserción/sobreescritura). o Toggle Current Fold: Cuando se explicó la zona de edición se decía que se pueden ocultar bloques de código independientes como declaraciones de estructuras, funciones, bloques if-else, bloques while o do-while, bloques for o incluso la propia función principal (main). Pues bien, la opción Toggle Current Fold permite ocultar o mostrar estos bloques de código independientes. Para ello hay que situar el cursor al comienzo del bloque (a la derecha del símbolo de minimizar/maximizar) y pulsar sobre esta opción. Si el bloque está oculto se mostrará, mientras que si se - 49 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. estaba mostrando se ocultará. Esta opción se encuentra desactivada si no hay ningún fichero en la zona de edición. o Toggle All Folds: Esta opción permite ocultar todos los bloques de código independientes tal y como se ha explicado en la opción anterior. La única diferencia que presenta respecto de dicha opción es que no influye la situación del cursor a la hora de ejecutar la acción puesto que todos los bloques serán ocultados/mostrados. Esta opción se encuentra desactivada si no hay ningún fichero en la zona de edición. o End of Line: Esta opción permite visualizar el fin o avance de línea (LF) y el retorno de carro (CR) en cada una de las líneas del fichero que se encuentra en la zona de edición. El avance de línea y el retorno de carro ya fueron explicados en la opción File Format del menú Edit. o Line Numbers: Esta opción permite mostrar (opción activada) o esconder (opción desactivada) los números de línea que se encuentran a la izquierda del fichero cargado en la zona de edición. o Indentation Guides: Esta opción permite mostrar (opción activada) o esconder (opción desactivada) los puntos suspensivos azules situados en cada tabulación que ayudan a ordenar el código para facilitar su seguimiento y a localizar el inicio y fin de bloques if-else, do-while, while, bucles for, etc. o Margin: Esta opción permite mostrar (opción activada) o esconder (opción desactivada) el margen situado entre los números de línea y el código del fichero cargado en la zona de edición. o Fold Margin: Esta opción permite mostrar (opción activada) o esconder (opción desactivada) el margen y la llave de seguimiento situados en los bloques de código independientes ya explicados. El margen y la llave de - 50 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. seguimiento permiten una rápida localización de dichos bloques por lo que no es recomendable su ocultación. o Project Window: Puede activarse también pulsando simultáneamente las teclas Alt y 0. Esta opción permite mostrar (opción activada) o esconder (opción desactivada) la zona de workspace. o Output Window: Puede activarse también pulsando simultáneamente las teclas Alt y 2. Esta opción permite mostrar (opción activada) o esconder (opción desactivada) la zona de salida. - 51 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Project: Consta de siete opciones como son New Project (Nuevo Proyecto), Open Project (Abrir Proyecto), Save Project (Guardar Proyecto), Close Project (Cerrar Proyecto), Add To Project (Añadir al Proyecto), Settings (Ajustes) y Export Makefile (Exportar fichero Makefile). o New Project: Puede activarse también pulsando simultáneamente las teclas Ctrl y N. Esta opción presenta el mismo comportamiento que la opción New del menú File ya explicado y se encuentra activada si no hay ningún proyecto en la zona de workspace. o Open Project: Esta opción permite abrir un abrir un fichero de proyecto MinGWStudio Project Files (extensión *.msp o *mdsp). Esta opción se encuentra activada si no hay ningún proyecto en la zona de workspace. A continuación se muestra una captura de la ventana que aparece al pulsar la opción y que permite seleccionar el proyecto a abrir. o Save Project: Esta opción permite guardar los cambios realizados en la configuración del proyecto mediante la opción Settings que se explicará posteriormente y que forma parte de este menú. Esta opción no guarda cambios realizados en los ficheros del proyecto. - 52 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Close Project: Esta opción cierra el proyecto que se encuentre abierto en la zona de workspace. Antes de cerrar el proyecto aparece un cuadro de confirmación de cierre de proyecto. Además, en caso de que alguno de los ficheros del proyecto haya sido modificado aparecerá un segundo cuadro que preguntará acerca de la posibilidad de guardar los cambios realizados. o Add To Project: Esta opción permite añadir al proyecto ficheros de proyecto u otro tipo de ficheros. Para ello, existen dos opciones diferentes que se muestran en un submenú: New y Files. New presenta el mismo comportamiento que la opción New Project de este mismo menú y que la opción New del menú File. Por otra parte, el submenú Files permite añadir ficheros al proyecto. Estos ficheros pueden tener cualquiera de las extensiones soportadas por el programa y que fueron explicadas en la opción Open del menú File. o Settings: Esta opción permite establecer una serie de propiedades del proyecto agrupadas en cuatro categorías: General (General), Compile (Compilar), Link (Enlazar) y Resources (Recursos). La categoría General permite escribir datos relativos al directorio de trabajo, a los argumentos del programa y a los directorios de ficheros de salida (tanto intermedios como de salida). La categoría Compile permite escribir definiciones del preprocesador, opciones extra de compilación y directorios adicionales de include. Además, permite especificar opciones adicionales relativas a warnings, información de Debugging (depuración), niveles de optimización y lenguaje C++ (información en tiempo de ejecución y gestión de excepciones). A continuación se muestra una captura del cuadro Project Settings en la categoría General, que es la que aparece por defecto al pulsar sobre la opción Settings. - 53 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Export Makefile: Esta opción crea un fichero Makefile a partir del fichero que se encuentre abierto en la zona de edición. El fichero Makefile ya fue explicado al detallar la categoría Build del submenú Options del menú Edit. El fichero Makefile aparecerá en el mismo directorio del proyecto una vez que se pulsa esta opción. A continuación se muestra una captura del fichero Makefile creado a partir de un fichero. - 54 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. - 55 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Build: Consta de diez opciones como son Compile (Compilar), Build (Construir), Rebuild All (Reconstruir todo), Build All Configurations (Construir todas las configuraciones), Build and Execute (Construir y Ejecutar), Clean (Limpiar), Clean All Configurations (Limpiar todas las configuraciones), Stop (Parar), Configuration Execute (Ejecutar) (Establecer y Set configuración Active activa). Ninguna de estas opciones estará activa a menos que haya un proyecto en la zona de workspace. En tal caso estarán todas las opciones activas menos Compile que requiere que haya un fichero abierto en la zona de edición y Stop que sólo estará activa durante el tiempo que se esté llevando a cabo alguna de las acciones situadas por encima de ella en el menú. o Compile: Puede activarse también pulsando simultáneamente las teclas Ctrl y F7. Esta opción permite compilar el fichero que se encuentre abierto en la zona de edición. Los mensajes que aparecen en la zona de salida ya se explicaron cuando se comentó dicha zona. o Build: Puede activarse también pulsando la tecla F7. Esta opción permite compilar y enlazar el fichero que se encuentre abierto en la zona de edición. Los mensajes que aparecen en la zona de salida ya se explicaron cuando se comentó dicha zona. o Rebuild All: Esta opción compila y enlaza el fichero que se encuentre abierto en la zona de edición tras eliminar los ficheros intermedios y ficheros de salida generados en anteriores compilaciones, enlazados y ejecuciones con la configuración Debug que se explicará en el siguiente punto. Una vez ejecutada, se habrá creado la carpeta Debug en el directorio del proyecto y contendrá el fichero con extensión *.o generado tras la compilación y el fichero con extensión *.exe generado tras el enlazado. - 56 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Build All Configurations: Un proyecto de MinGW tiene configuraciones diferentes para las versiones de lanzamiento (Release) y de depuración (Debug) del programa. Como sus nombres indican, la versión Debug se construye para depuración mientras que la versión Release se construye para la distribución final del programa en su lanzamiento. Si se crea un programa con MinGW, éste crea automáticamente las configuraciones y establece opciones apropiadas por defecto y otros ajustes. Con las opciones por defecto: La configuración Debug del programa es compilada con información simbólica de depuración y sin optimización. La optimización complica la depuración porque la relación entre el código fuente y las instrucciones generadas es de mayor complejidad. La configuración Release del programa está completamente optimizada y no contiene información simbólica de depuración. Una vez explicadas las dos configuraciones posibles, la opción Build All Configurations crea ambas configuraciones en el directorio del proyecto. En dicho directorio aparecen, por tanto, la carpeta Debug y la carpeta Release con sus respectivas configuraciones. Si no se pulsa esta opción, el compilador creará únicamente la versión Debug, que es la establecida por defecto. o Build and Execute: Esta opción construye el programa (ver comportamiento de la opción Build explicada anteriormente) y lo ejecuta. Por tanto, compila, enlaza y ejecuta el fichero que se encuentre abierto en la zona de edición. En caso de que la compilación o el enlazado presenten errores la ejecución se suspenderá y aparecerá un cuadro con el mensaje ‘Cannot execute program’ (No se puede ejecutar el programa). - 57 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Clean: Esta opción borra los ficheros intermedios y los ficheros de salida generados con la configuración Debug. Elimina, por tanto, la carpeta Debug del directorio del proyecto. o Clean All Configurations: Esta opción borra los ficheros intermedios y los ficheros de salida generados con las configuraciones Debug y Release. Elimina, por tanto, las carpetas Debug y Release del directorio del proyecto. o Stop: Esta opción permite parar la ejecución de las acciones situadas por encima de ella en el menú Build. Permite, por tanto, parar la ejecución de las opciones Compile, Build, Rebuild All, Build All Configurations, Build and Execute, Clean y Clean All Configurations una vez que alguna de ellas haya sido pulsada y sin que haya terminado la ejecución de la tarea que realiza. o Execute: Puede activarse también pulsando simultáneamente las teclas Ctrl y F5. Esta opción ejecuta el programa (el fichero *.exe generado tras el enlazado en la carpeta Debug del directorio del proyecto). En caso de que el programa no haya sido compilado o enlazado, MinGW desplegará un cuadro informando acerca de la situación (The target is out of date) y preguntando si se quiere realizar el compilado y enlazado. Este cuadro se muestra a continuación. o Set Active Configuration: Esta opción permite seleccionar la configuración (Debug o Release) de la versión del proyecto. La configuración por defecto es Debug. Ambas configuraciones ya fueron explicadas anteriormente (ver opción Build All Configurations). - 58 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Debug: Este menú será explicado posteriormente en el apartado 5.1 ‘Menú Debug’ del capítulo 5. - 59 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Tools: Consta de una única opción como es Resource Editor (Editor de recursos). o Resource Editor: Puede activarse también pulsando simultáneamente las teclas Ctrl y R. Esta opción abre el editor de recursos. El editor de recursos permite crear ficheros resource script (extensión *.rc) de forma rápida e intuitiva. El editor cuenta con una interfaz gráfica muy cómoda para diseñar el aspecto de ventanas, iconos, botones, barras de herramientas y otros muchos tipos de recursos gráficos. Hay que recordar que los ficheros *.rc son empleados por GTK+ (GIMP Tool Kit) para tratar las opciones predeterminadas de las aplicaciones. Con ellos se pueden cambiar los colores de cualquier control, poner un dibujo de fondo, etc. GTK+ es un grupo importante de bibliotecas o rutinas para desarrollar interfaces gráficas de usuario (GUI) mediante C, C++ y otros lenguajes de programación. A continuación se muestra una captura del editor de recursos. - 60 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Window: Consta de ocho opciones como son Close (Cerrar), Close All (Cerrar todo), Cascade (Cascada), Tile Horizontally (Mosaico Horizontal), Tile Vertically (Mosaico Vertical), Arrange Icons (Ordenar iconos), Next (Siguiente) y Previous (Anterior). Además, a continuación de las ocho opciones muestra el nombre de los ficheros que se encuentran abiertos ordenados de arriba hacia abajo en orden de apertura (el primero será el que se abrió primero y el último será el que se abrió más recientemente). Además, a la izquierda del fichero que se encuentre abierto en la zona de edición se mostrará el símbolo indicando dicha situación. o Close: Esta opción cierra el fichero que se encuentre abierto en la zona de edición. Además, elimina su correspondiente pestaña de la zona superior de la zona de edición y la entrada con su nombre en el menú Window. o Close All: Esta opción cierra todos los ficheros abiertos. Además, elimina sus correspondientes pestañas de la zona superior de la zona de edición y las entradas con sus nombres en el menú Window. Como resultado, la zona de edición queda en color gris al igual que al iniciar la aplicación. o Cascade: Esta opción permite visualizar los ficheros abiertos en cascada dentro de la zona de edición tal y como se muestra a continuación. - 61 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Tile Horizontally: Esta opción permite visualizar los ficheros abiertos en mosaico horizontal dentro de la zona de edición tal y como se muestra a continuación. - 62 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Tile Vertically: Esta opción permite visualizar los ficheros abiertos en mosaico vertical dentro de la zona de edición tal y como se muestra a continuación. o Arrange Icons: Esta opción permite ordenar las ventanas que se encuentren minimizadas en la zona de edición. Si varias ventanas se encuentran minimizadas en la zona de edición tras visualizarlas mediante mosaico horizontal, vertical o cascada esta opción permite ordenarlas en el mismo orden en que fueron minimizadas. De esta forma se sitúan los iconos de las ventanas ordenados en la parte inferior izquierda de la zona de edición. o Next: Esta opción permite activar el fichero (la ventana) siguiente al que se encuentra activo en los modos de visualización en cascada, mosaico horizontal y mosaico vertical. De este modo, se activa la siguiente ventana y el cursor se sitúa donde se había quedado la última vez que dicho fichero estuvo activo. Si nunca lo estuvo, se situará al comienzo del fichero. - 63 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Previous: Esta opción permite activar el fichero (la ventana) anterior al que se encuentra activo en los modos de visualización en cascada, mosaico horizontal y mosaico vertical. De este modo, se activa la ventana anterior y el cursor se sitúa donde se había quedado la última vez que dicho fichero estuvo activo. Si nunca lo estuvo, se situará al comienzo del fichero. - 64 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Help (About MinGW Developer Studio): Esta opción abre un cuadro de diálogo con créditos acerca de la aplicación (versión, fecha de creación y software que se emplea –GNU GCC, MINGW, wxWindows, wxStyledTextCtrl, Scintilla and SciTE y ResEd – con una breve explicación de cada uno y un enlace web). - 65 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 4.2.2. Barra de Herramientas. La barra de herramientas es un sistema cómodo y rápido para ejecutar directamente cualquier opción de los menús explicados en el apartado anterior. Consta de veintisiete iconos que permiten realizar acciones como crear un nuevo proyecto, abrir un fichero, compilar un programa, depurar un programa, solicitar ayuda, etc. Cada uno de los iconos será explicado a continuación mediante una tabla que muestra la equivalencia entre los iconos de la barra de herramientas y la opción del menú que es ejecutada cuando se pulsa el icono. Icono Acción ejecutada File New (Ctrl+N) File Open (Ctrl+O) File Save (Ctrl+S) File Save All Edit Cut (Ctrl+X) Edit Copy (Ctrl+C) Edit Paste (Ctrl+V) Edit Undo (Ctrl+Z) Edit Redo (Ctrl+Y) View Project Window (Alt+0) View Output Window (Alt+2) Previous (Alt+Left Arrow) Next (Alt+Right Arrow) Build Compile (Ctrl+F7) Build Build (F7) Build Stop Build Execute (Ctrl+F5) Debug Go (F5) Debug Toggle Breakpoint (F9) Debug Step Into (F11) Debug Step Over (F10) Debug Step Out of Function (Shift+F11) Debug Run to Cursor (Ctrl+F10) Debug QuickWatch (Shift+F9) File Print Preview File Print (Ctrl+P) Help About MinGW Developer Studio - 66 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 5 Depuración de Programas (Debugging) - 67 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 5. Depuración de programas (Debugging). Debugging es el nombre que recibe el proceso de eliminación y limpieza de bugs (errores) de los programas. Para realizar la depuración de programas se emplea el debugger, que es una herramienta diseñada para revisar las instrucciones de un programa paso a paso y examinar su estado en cada paso. El Debugging comienza en cuanto el usuario se empieza a preguntar las razones por las que su programa no produce los resultados deseados. La primera tarea que se debe realizar es asegurarse de que el código C/C++ compila y enlaza sin errores. Si se produce algún error, el código debe ser modificado de tal manera que no ocurra. La segunda tarea que se debe realizar es examinar el código y comparar los resultados deseados con los que se están obteniendo. Sin embargo, en muchas ocasiones sucede que tras realizar un examen profundo del código sigue sin aparecer el error. Es en estos casos en los que es necesario emplear el debugger, que puede realizar las siguientes acciones: Recorrer las sentencias del programa paso a paso, bien “over” (por encima de) o “into” (dentro de) las funciones. En el primer caso (over) se omite el recorrido dentro de las funciones mientras que en el segundo caso se recorren las sentencias de las funciones y se vuelve a la función principal. Ejecutar el programa hasta un cierto punto (bien hasta el cursor o hasta un breakpoint) y luego detener la ejecución. En el primer caso (cursor) se ejecuta el programa hasta el lugar del código donde esté situado el cursor antes de comenzar el debugging. En el segundo caso (breakpoint) el programa se ejecutará hasta un breakpoint o punto de parada que se habrá situado en el código antes de comenzar el debugging. Mostrar los valores (o el contenido) de las variables en cada punto durante la ejecución del programa. - 68 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 5.1. Menú Debug. El menú Debug consta de nueve opciones como son Go (Iniciar), Stop Debugging (Detener la depuración), Step Into (Ejecutar dentro de), Step Over (Ejecutar por encima de), Run to Cursor (Ejecutar hasta el cursor), Step Out of Function (Salir de la función), Back trace (Visualización de origen), Toggle Breakpoint (Situar/Eliminar breakpoint) y QuickWatch (Vista rápida). o Go: Puede activarse también pulsando la tecla F5. Esta opción inicia la depuración del fichero que se encuentre abierto en la zona de edición. Sin embargo, la depuración del programa es tan rápida que no permite ver paso a paso la evolución del mismo. Esto puede evitarse situando un breakpoint (mediante la opción Toggle Breakpoint que se explicará posteriormente) en el punto del código donde se quiere detener la depuración o bien por medio de la opción Run to Cursor que se explicará posteriormente. La pestaña Debug situada en la zona de salida mostrará el mensaje ‘Debug has started’ (La depuración ha comenzado) cuando se pulse esta opción y ‘Debug has stopped’ (La depuración ha finalizado) cuando finalice la depuración tal y como se muestra a continuación. o Stop Debugging: Puede activarse también pulsando simultáneamente las teclas Shift y F5. Esta opción detiene la depuración del fichero que se encuentre abierto en la zona de edición. La depuración puede haberse iniciado por medio de la opción Go, la opción Step Into o la opción Run to cursor. Al pulsar esta opción la pestaña Debug situada en la zona de - 69 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. salida mostrará el mensaje ‘Debug has stopped’ (La depuración ha finalizado). o Step Into: Puede activarse también pulsando la tecla F11. Esta opción permite la ejecución paso a paso del fichero que se encuentre abierto en la zona de edición. La primera vez que se pulse esta opción sin haberse iniciado la depuración, ésta comenzará. Cuando comienza la depuración aparece la ventana de consola y una flecha amarilla se sitúa a la derecha del número de línea de la primera sentencia del programa. Si se pulsa de nuevo se avanzará por medio de la flecha amarilla hasta la siguiente sentencia del programa y así sucesivamente siguiendo el flujo de ejecución del programa. En caso de que una sentencia sea una llamada a una función desde la función principal, la opción Step Into permite saltar directamente a la primera sentencia de la función y ver las sentencias de ésta hasta que vuelve o retorna a la función principal. Una vez que se pulsa esta opción estando en la última sentencia del programa la ventana de consola contendrá la ejecución completa del programa con sus respectivas salidas y la pestaña Debug situada en la zona de salida mostrará el mensaje ‘Debug has stopped’ (La depuración ha finalizado). A continuación se muestra una captura del debugging una vez se ha pulsado la opción Step Into. - 70 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Como se puede ver en la captura sobre estas líneas, cuando el debugger llega a la sentencia de llamada a la función Suma (res=Suma(a,b);) y se pulsa la opción Step Into, la flecha amarilla avanza hasta la primera sentencia de la función (suma=0;) y permite revisar su comportamiento. Si se vuelve a pulsar repetidamente, el debugger continuará revisando las sentencias de la función hasta llegar al final (denotado por ‘}’) y volverá a la función llamante (main). o Step Over: Puede activarse también pulsando la tecla F10. Esta opción realiza exactamente lo mismo que la opción anterior (Step Into) con la diferencia de que si una sentencia es una llamada a una función desde la función principal no salta a la primera sentencia de la función y permite revisar sus sentencias sino que salta a la siguiente sentencia de la función principal tras haber realizado las acciones que desempeñaba la función. En resumen, se pasa a la siguiente sentencia de la función principal omitiendo la revisión de todas las sentencias de la función aunque a - 71 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. efectos de resultado es como si se hubiera realizado. De este modo se ahorra tiempo de revisión de funciones donde se descarta la aparición de errores (bugs). A continuación se muestra una captura de la ejecución del debugger una vez se ha pulsado la opción Step Over. Como se puede ver, cuando el debugger llega a la sentencia de llamada a la función Suma (res=Suma(a,b);) y se pulsa la opción Step Over, la flecha amarilla avanza hasta la siguiente sentencia de la función principal (printf) omitiendo la revisión de las sentencias de la función Suma. o Run to Cursor: Puede activarse también pulsando simultáneamente las teclas Ctrl y F10. Esta opción permite llevar a cabo la depuración del fichero que se encuentre abierto en la zona de edición hasta el lugar donde se haya situado el cursor antes de iniciar la depuración. De este modo se ejecutan las sentencias del programa sólo hasta un determinado punto especificado por el usuario antes de comenzar la depuración. - 72 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Step Out of Function: Puede activarse también pulsando simultáneamente las teclas Shift y F11. Esta opción sólo se encuentra activa cuando el debugger se encuentra situado en una sentencia de una función y permite regresar a la función principal omitiendo la revisión del resto de sentencias de la función. Cuando regresa a la función principal, las sentencias restantes no se revisan aunque sus acciones se han ejecutado. o Back trace: Puede activarse también pulsando la tecla F12. Esta opción imprime en la pestaña Debug de la zona de salida información acerca de la sentencia que se está revisando. La información que se muestra es: level (nivel de profundidad), addr (dirección de memoria de la instrucción), func (nombre de la función), file (nombre del fichero que se está depurando) y line (número de línea de la sentencia). El nivel de profundidad será el más alto si se trata de la función principal, el anterior al de la función principal si se trata de una función llamada por la función principal, el anterior al anterior al de la función principal si se trata de una función llamada por una función llamada por la función principal y así sucesivamente. Cuando se pulsa la opción Back trace sobre una sentencia de una función se muestra información acerca de la sentencia de la función y acerca de la sentencia de la función principal que llamó a dicha función. A continuación se muestra una captura de la zona de salida una vez pulsada la opción Back trace estando el debugger en una sentencia de una función. - 73 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Toggle Breakpoint: Puede activarse también pulsando la tecla F9. Esta opción añade/elimina un punto de parada (breakpoint) en la sentencia del programa donde se sitúe el cursor. Como ya se ha comentado, los breakpoints sirven para ejecutar el debugger hasta el lugar donde estén situados. La sentencia en la que se sitúe un breakpoint se distinguirá del resto ya que aparecerá un círculo de color rojo a la derecha del número de línea. A continuación se muestra una captura de la opción Toggle Breakpoint en la que se observa el punto rojo situado al lado de la sentencia (printf) donde se ha colocado el breakpoint. - 74 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o QuickWatch: Puede activarse también pulsando simultáneamente las teclas Shift y F9. Esta opción abre una ventana de observación de variables que permite visualizar el valor de las variables del programa a medida que avanza el debugger. A continuación se muestra una captura de la ventana de observación que ayudará en la explicación. En el cuadro de texto Expression se escribe el nombre de la variable que se desea observar. Al pulsar el botón Add Watch, dicha variable se introducirá en el cuadro Current value e inicialmente tomará un valor desconocido (??). Al pulsar una variable del cuadro Current Value se podrán realizar las siguientes acciones: eliminarla (botón Delete) o cambiarle el valor (botón Set Value). La opción Set Value es útil para ver - 75 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. los resultados que se producirían en caso de que las variables tomasen otros valores. El botón Delete All elimina todas las variables del cuadro Current value mientras que el botón Close cierra la ventana de observación. Una vez que todas las variables que se desean observar han sido introducidas y aparecen en el cuadro Current value ya se puede iniciar el debugger para ver los valores que van tomando. De esta forma en cada paso del debugger se observarán los valores que toman las distintas variables del cuadro Current value y se podrá modificar el programa para obtener los resultados esperados. Para ello, con la opción Set Value se pueden modificar los valores de las variables y ver la ejecución que se produce. A continuación se muestra la ventana de observación de la opción QuickWatch al ejecutar un programa con el debugger. - 76 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. La ventana de observación del ejemplo anterior se produjo cuando el debugger se encontraba en la segunda vuelta del bucle for (i=2) por lo que todas las variables tomaban un valor salvo res puesto que la función aún no había terminado su ejecución. Es por ello que en dicha variable aparece el mensaje “No symbol ‘res’ in current context” informando acerca de dicha situación. Existe otra forma alternativa de ver los valores que toman las variables en cada sentencia en la que se detiene el debugger. Esta forma consiste en situar el cursor encima de la variable que se quiere observar en la zona de edición. De esta forma aparecerá una etiqueta que mostrará el mismo valor que se muestra en la ventana de observación de la opción QuickWatch. Esta manera de ver el valor de las variables es más rápida que con la opción QuickWatch si bien no permite monitorizar todas las variables en una misma ventana, algo que sí es posible con la citada opción. - 77 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Por último hay que comentar que MinGW Developer Studio no puede cerrarse si el debugger está funcionando por lo que es necesario detener su ejecución si se quiere abandonar la aplicación. Por ello, se mostrará un cuadro informando acerca de dicha situación en caso de intentar salir del programa con el debugger funcionando. Dicho cuadro se muestra a continuación. El cuadro de la figura muestra el mensaje ‘You cannot close the Project while debugging. Select the Stop Debugging befote closing the project’ (No puedes cerrar el proyecto mientras está funcionando el debugger. Selecciona la opción Stop Debugging antes de cerrar el proyecto) para indicar la situación comentada en el párrafo anterior. - 78 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. PARTE II: Funcionamiento del compilador en la parte que se corresponde a Orientación a Objetos (C++) - 79 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 1 Introducción - 80 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 1. Introducción. El compilador MinGW Developer Studio permite llevar a cabo programación orientada a objetos (POO) por medio del lenguaje de programación C++, uno de los más empleados en la actualidad. Se puede decir que C++ es un lenguaje híbrido, ya que permite programar tanto en estilo procedimental (orientado a algoritmos), como en estilo orientado a objetos, como en ambos a la vez. Además, también se puede emplear mediante programación basada en eventos para crear programas que usen interfaz gráfica de usuario (GUI). Como lenguaje procedimental se asemeja al C y es compatible con él, aunque presenta ciertas ventajas. Como lenguaje orientado a objetos se basa en una filosofía completamente distinta, que exige del programador un completo cambio de mentalidad. El nacimiento de C++ se sitúa en el año 1980, cuando Bjarne Stroustrup, de los laboratorios Bell, desarrolló una extensión de C llamada “C with Classes” (C con Clases) que permitía aplicar los conceptos de la programación orientada a objetos con el lenguaje C. Stroustrup se basó en las características de orientación a objetos del lenguaje de programación Simula, aunque también tomó ideas de otros lenguajes importantes de la época como ALGOL68 o ADA. Durante los siguientes años, Stroustrup continuó el desarrollo del nuevo lenguaje y en 1983 se acuñó el término C++ (C Plus Plus). En 1985, Bjarne Stroustrup publicó la primera versión de “The C++ Programming Language” (El lenguaje de programación C++), que a partir de entonces se convirtió en el libro de referencia del lenguaje. En la actualidad, este lenguaje se encuentra estandarizado a nivel internacional mediante el estándar ISO/IEC 14882:1998 con el título “Information Technology – Programming Languages – C++”, publicado el 1 de Septiembre de 1998. En el año 2003 se publicó una versión corregida del estándar (ISO/IEC - 81 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 14882:2003). Finalmente, en la actualidad se está preparando una nueva versión del lenguaje, llamada “C++0X”, que se espera que esté preparada para el año 2010. En C, la unidad de programación es la función, con lo cual, se trata de una programación orientada a la acción. Por el contrario, en C++ la unidad de programación es la clase a partir de la cual, los objetos son producidos. Se trata, pues, de una programación orientada a objetos. Las bibliotecas estándar de C++ proporcionan un conjunto extenso de capacidades de entrada/salida. C++ usa entrada/salida de tipo seguro por lo que no podrán introducirse datos equivocados dentro del sistema. Se pueden especificar entradas/salidas de tipos definidos por el usuario, así como de tipos estándar. Esta extensibilidad es una de las características más valiosas de este lenguaje de programación. C++ permite un tratamiento común de entradas/salidas de tipos definidos por usuario. Este tipo de estado común facilita el desarrollo de software en general y de la reutilización de software en particular. Las principales ventajas que presenta el lenguaje C++ son: o Difusión: al ser uno de los lenguajes más empleados en la actualidad, posee un gran número de usuarios y existe una gran cantidad de libros, cursos, páginas Web, etc. dedicados a él. o Versatilidad: C++ es un lenguaje de propósito general, por lo que se puede emplear para resolver cualquier tipo de problema. o Portabilidad: el lenguaje está estandarizado y un mismo código fuente se puede compilar en diversas plataformas. - 82 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Eficiencia: C++ es uno de los lenguajes más rápidos en cuanto a ejecución. o Herramientas: existe una gran cantidad de compiladores, depuradores, librerías, etc. - 83 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 2 Creación de aplicaciones C++ en MinGW Developer Studio - 84 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 2. Creación de aplicaciones C++ en MinGW Developer Studio. Inicialmente, el área de trabajo del entorno de desarrollo está vacía. Para crear ahora la estructura de una nueva aplicación C++, se procede del siguiente modo: a. Se elige la opción New en el menú File (o se pulsan las teclas Ctrl y N simultáneamente) o bien se pulsa el botón de la barra de herramientas. b. A continuación, se presenta una ventana en la que se puede elegir el tipo de aplicación que se desea crear. Se selecciona la pestaña Projects y la aplicación de tipo Win32 Console Application. Ahora se procede a nombrar el proyecto escribiendo el nombre que se desea en el cuadro Project name. En el cuadro Location se permite especificar la ruta de acceso al directorio, es decir, el directorio donde se creará la carpeta de nombre igual al del proyecto y que contendrá todos los ficheros relativos - 85 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. al proyecto (ejecutables, código fuente, etc.). Una vez especificado el nombre del proyecto y la ruta de acceso se confirma el cuadro de diálogo pulsando OK y ya se ha creado un proyecto nuevo. En el directorio especificado en el cuadro Location se habrá creado un fichero llamado nombre_del_proyecto.msp (MinGWStudio Project Files). Puede darse la situación de que el fichero creado tenga extensión *.mdsp en vez de *.msp. Esto se debe a que algunas versiones del compilador ponen dicha extensión a los ficheros de proyecto. c. El paso siguiente es crear un fichero y añadirlo al proyecto actualmente vacío. Se elige la opción New del menú File (o se pulsan las teclas Ctrl y N simultáneamente) o se pulsa el botón de la barra de herramientas. Se selecciona la pestaña Files y el fichero de tipo C/C++ Source File para crear un fichero de lenguaje de programación C++ (*.cpp) que contenga el código fuente. Se nombra el fichero en el cuadro File name y se confirma pulsando OK. El campo Location no debe ser modificado ya que por defecto se muestra la ruta de acceso al directorio del proyecto creado anteriormente. Además, la checkbox Add to project se encuentra activada para añadir el fichero al proyecto que se había creado previamente. Por tanto, la ruta de acceso y la checkbox no deben ser modificadas. En el directorio del proyecto se habrá creado nombre_del_fichero.cpp (C Plus Plus Source File). - 86 - un fichero llamado Programación Orientada a Objetos en C mediante MinGW Developer Studio. d. El entorno ya está listo para introducir el código en la zona de edición. - 87 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 2.1. Opciones de MinGW Developer Studio relacionadas con C++. El compilador dispone de una serie de opciones relacionadas con el lenguaje de programación C++ que se verán a continuación. o Comentarios en estilo C++: el compilador dispone de una opción que permite convertir un texto seleccionado en comentario C++ (cada línea de comentario precedida de ‘//’). Esta opción se encuentra en el menú Edit Advanced Make Selection C++ style comment y es preciso seleccionar el texto a convertir en comentario C++ antes de pulsarla. A continuación se muestra un ejemplo de comentario C++. // stdafx.h: include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently o Manejo de excepciones e información en tiempo de ejecución: el compilador dispone de dos opciones relativas al lenguaje C++ que permiten habilitar o deshabilitar el manejo de excepciones y la información de tipo Runtime. El manejo de excepciones es una estructura de control del lenguaje C++ diseñada para manejar condiciones anormales que pueden ser tratadas por el mismo programa que se desarrolla. La información de tipo Runtime (RTTI – Run-Time Type Information) es un sistema C++ que guarda en memoria información acerca del tipo de datos de un objeto en tiempo de ejecución. RTTI resulta útil cuando se trabaja con punteros a objetos en los que, en general, no se puede determinar el tipo de objeto al que referencian. Las dos opciones anteriormente descritas se encuentran en el menú Project Settings y en la pestaña Compile. En dicha pestaña hay una groupbox llamada C++ Language que contiene ambas opciones. A continuación se muestra una captura del cuadro Settings en la pestaña Compile donde se muestran las opciones relativas a C++. - 88 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Cuando se desarrollan aplicaciones orientadas a objetos es necesario declarar las clases (este concepto se verá en el capítulo 3) en ficheros independientes. El tipo de fichero que se emplea para declarar las clases es el fichero de cabecera (C/C++ Header File). Para crear un fichero de cabecera y añadirlo al proyecto se elige la opción New del menú File (o se pulsan las teclas Ctrl y N simultáneamente) o se pulsa el botón de la barra de herramientas. Se selecciona la pestaña Files y el fichero de tipo C/C++ Header File para crear un fichero de cabecera (*.h) que contenga la declaración de la clase. Se nombra el fichero en el cuadro File name con el mismo nombre que se le quiera dar a la clase y se confirma pulsando OK. El campo Location no debe ser modificado ya que por defecto se muestra la ruta de acceso al directorio del proyecto creado anteriormente. Además, la checkbox Add to project se encuentra activada para añadir el fichero de cabecera al proyecto que se había creado previamente. Por tanto, la ruta de acceso y la checkbox no deben ser modificadas. En el directorio del proyecto se habrá creado un fichero llamado nombre_de_la_clase.h. - 89 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 3 Programación Orientada a Objetos (POO) en C++ - 90 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 3. Programación Orientada a Objetos (POO) en C++. Para explicar la POO (Programación Orientada a Objetos) se partirá de un ejemplo sencillo en el que se verán algunos conceptos clave. A continuación se muestra un objeto de la clase Persona. La zona amarilla muestra los atributos del objeto (nombre y edad) mientras que el resto de colores muestran los métodos del objeto (getNombre, getEdad, setNombre y setEdad), es decir, las acciones y tareas que puede desempeñar dicho objeto. A los atributos de un objeto nunca se tendrá acceso directo (como una especie de caja negra) y sólo se accederá a ellos a través de los métodos. Se necesitarán, pues, dos tipos de métodos para manejar los objetos: los que obtengan los datos (getters) y los que asignen datos (setters). Los métodos definen lo que se conoce por interfaz de un objeto, es decir, la parte que maneja el usuario y a la que se puede acceder. Los atributos, sin embargo, forman parte de la zona oculta al usuario y a la que no se tiene acceso. Las peticiones que se pueden hacer a un objeto se encuentran definidas en su interfaz y es el tipo de objeto el que determina la interfaz. La interfaz establece qué peticiones pueden hacerse a un objeto particular. La forma de acceder a los objetos es invocando sus métodos de la siguiente manera: objeto.método(). A continuación se muestran objetos creados de la clase Persona: - 91 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Ejemplos de tareas a realizar con estos objetos: Obtener el nombre de la persona p1 y la edad de la persona p4. p1.getNombre(); p4.getEdad(); // Devuelve “Pedro” // Devuelve “23” Cambiar el nombre de la persona p2 y la edad de la persona p3. p2.setNombre(“Alberto”); p3.setEdad(38); Una vez vistos en la práctica el funcionamiento de los objetos, éstos se pueden definir como entidades complejas provistas de datos (propiedades, atributos) y comportamiento (métodos). Posteriormente se verá la relación entre los objetos y la clase a la que pertenecen (en el ejemplo, Persona). A continuación se explicará en detalle lo que es una clase. - 92 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 3.1. Clase. La programación orientada a objetos se basa en encapsular datos (atributos) y funciones o comportamientos (métodos) juntos en estructuras llamadas clases. Las clases responden a la necesidad del programador de construir objetos o tipos de datos que respondan a sus necesidades y se emplean para modelar objetos del mundo real. Para explicar el concepto de clase se comenzará con un ejemplo sencillo que ayude a entenderlo. Supóngase que se quiere preparar un flan. Para ello se necesitarán una serie de ingredientes como azúcar, huevo, leche, etc. Todos estos ingredientes se mezclarán y se introducirán en un molde, que es el que se meterá en el horno. Una vez finalizado el tiempo de horneo se obtendrá el flan. Si se quisiera preparar otro flan igual se haría lo mismo y así sucesivamente. El mismo molde serviría para elaborar un número infinito de flanes. Pues bien, algo parecido sucede con los objetos y la clase a la que pertenecen. Todos los objetos de una misma clase comparten los mismos atributos (en el ejemplo, ingredientes) y la clase es el molde que permite su creación. En la clase estarán definidas todas las propiedades y funcionalidad común a los objetos que pertenezcan a ella. Los objetos, por tanto, heredan las propiedades y también el comportamiento de todas las clases a las que pertenezcan. Una clase se define como una estructura que define atributos e implementa métodos de cada objeto. La tarea principal de una clase es crear objetos. Las clases se definen mediante la palabra reservada class. - 93 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. A continuación se muestra la representación de la clase Persona del ejemplo del punto anterior. Como se puede ver en la figura sobre estas líneas, la clase Persona tiene dos atributos (zona verde) y cuatro métodos (zona roja). Los getters permiten obtener el nombre y la edad del objeto de la clase Persona mientras que los setters permiten modificar el nombre y la edad de dicho objeto. Existen dos tipos de clases: o Clases abstractas: son clases que tienen definidos sus métodos pero no su implementación. Ningún objeto puede pertenecer directamente a estas clases. Las clases que heredan (la herencia se verá en el capítulo 4) de una clase abstracta deben implementar sus métodos. Las clases abstractas se explican en detalle en el apartado 4.5.3 del capítulo 4. o Clases concretas: los objetos pueden pertenecer directamente a estas clases. - 94 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 3.2. Constructor y destructor. Ya se ha comentado que la clase es como una especie de molde que permite crear objetos. Para llevar a cabo la creación de objetos hace uso de un elemento llamado constructor. El constructor es un método que se declara con el mismo nombre que la clase y en el que se deben especificar los atributos a inicializar. Una clase sin constructor lo único que puede hacer es generar los objetos, pero vacíos (sin inicializar). El compilador MinGW Developer Studio proporciona un constructor por defecto que permite crear los objetos vacíos de forma automática. A continuación se muestra un ejemplo de un constructor: Persona(string nombre, int edad); A este constructor se le llama constructor personalizado ya que lo especifica el programador. Cuando no haya creado un constructor personalizado entonces será el constructor por defecto el que creará los objetos. En caso de que exista más de un constructor personalizado, éstos deben ser claramente diferenciables por sus argumentos (número o tipo). A este fenómeno mediante el cual varios métodos (el constructor también es un método) tienen el mismo nombre pero con distintos argumentos y definición se le llama sobrecarga. Cuando se invoca un método sobrecargado, el compilador analiza los argumentos de la llamada y, en función de su tipo, deduce cuál de las distintas versiones del método con ese nombre debe recibir el control. Debido a la sobrecarga, en C++ es obligatoria la declaración de los métodos y de los tipos de sus argumentos (int, float, string, char, etc.). A continuación se muestran tres constructores sobrecargados de la clase Persona: Persona(string nombre); Persona(int edad); Persona(string nombre, int edad); Como se ve en el ejemplo sobre estas líneas, los tres constructores se diferencian entre ellos en el número de argumentos salvo los dos primeros que - 95 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. tienen el mismo número. Sin embargo, estos dos se diferencian en el tipo de argumento por lo que el conflicto es inexistente. Por otra parte, existe un elemento que es invocado por el compilador de forma automática antes de la destrucción de un objeto. Este elemento recibe el nombre de destructor. Su declaración dentro de la clase es opcional y no devuelve tipo alguno ni admite parámetros. Se nombra con el nombre de la clase precedido del símbolo ‘~’. A continuación se muestra el destructor de la clase Persona: ~Persona(){} 3.3. Creación de objetos. Aunque el elemento que se encarga de la creación de objetos, el constructor, ya ha sido explicado no así el proceso de creación de objetos. Existen dos formas de crear objetos: o Automática (Nombre_Clase Nombre_objeto (argumentos)): El compilador se encarga de incluir el código necesario para crearlo antes de su primer uso y para destruirlo después de su último uso. Su alcance comienza en su declaración y termina con el bloque de código en el que se ha declarado (encerrado entre llaves). Si no pertenece a ningún bloque se crea al iniciarse el programa y se destruye inmediatamente antes de finalizar el programa. A continuación se muestran dos ejemplos de creación de objetos de forma automática: Persona per1(“Pedro”, 65); //Utilizando el constructor //Persona(string nombre, int edad); Persona per1(); //Utilizando el constructor por //defecto - 96 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Dinámica (operadores new y delete): Permite decidir el momento de la creación y destrucción de los objetos. Usa asignación dinámica de memoria (variables de tipo puntero). A continuación se muestran un ejemplo de creación y destrucción de objetos de forma dinámica: Persona *per1; //Declaración de la variable per1 de clase Persona per1 = new Persona(“Juana”, 27); //Creación del objeto per1 usando //el constructor Persona(string //nombre, int edad); delete per1; // Destrucción del objeto per1 Dependiendo de la forma elegida a la hora de crear un objeto cambiará la forma de acceder a sus métodos. Por ello se distinguen dos casos: o Si el objeto fue creado de forma automática, entonces el acceso a sus métodos se hará mediante el operador punto (.) tal y como se muestra a continuación. Persona per1(“Pedro”, 65); // Creación automática per1.setEdad(45); //NombreObjeto.método o Si el objeto fue creado de forma dinámica, entonces el acceso a sus métodos se hará mediante el operador flecha (->) tal y como se muestra a continuación. Persona *per1; // Declaración del objeto per1 = new Persona(“Juana”, 27); // Creación dinámica per1->setEdad(34); //NombreObjeto->método - 97 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 3.4. Especificadores de acceso. Al comienzo de este capítulo se decía que la interfaz de un objeto define el conjunto de métodos accesibles a dicho objeto. Además, se decía que los atributos forman parte de la zona oculta al usuario y a la que no se tiene acceso. Pues bien, los especificadores de acceso permiten determinar el nivel de acceso de los miembros de una clase y, por tanto, diferenciar entre la zona oculta y la interfaz. Se utilizan pues para determinar el nivel de ocultación de cada objeto (la ocultación se explicará en el apartado 4.2 del capítulo 4). Los especificadores de acceso permiten poner en práctica un principio básico de POO como es el encapsulamiento. Según este principio todo objeto tiene una capacidad de aislamiento (atributos y métodos) respecto a otros objetos de la misma o de otra clase. En definitiva, que el acceso a los atributos de un objetos se debe hacer por medio de sus métodos. Este principio se explicará en detalle en el apartado 4.1 del capítulo 4. Existen tres tipos de especificadores de acceso: o private: es opcional y se toma por defecto desde el principio de la definición de la clase hasta que aparece otro especificador de acceso. Los atributos y los métodos sólo son accesibles desde la propia clase. Es el especificador de acceso más restrictivo. Los atributos son siempre private ya que sólo tendrá acceso a ellos la propia clase puesto que no forman parte de la interfaz del objeto. o public: los atributos y los métodos son accesibles por cualquier clase. Es el especificador de acceso menos restrictivo. Los métodos son siempre public puesto que forman parte de la interfaz del objeto. o protected: los atributos y métodos son accesibles sólo por la clase que los contiene y todas aquellas que hereden de ésta (la herencia se explicará en el apartado 4.4 del capítulo 4). Se encuentra entre private y public, en un nivel restrictivo intermedio. - 98 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 3.5. Ficheros de cabecera y Espacio de nombres. A la hora de crear programas en C++ es necesario incluir dos sentencias que permitan posteriormente la utilización de instrucciones de las librerías de C++. Estas sentencias son: #include<iostream> y using namespace std; La instrucción #include<iostream> incluye el contenido del fichero de cabecera de flujo de entrada/salida (input output stream) en el código del programa. C++ dispone de dos jerarquías de clases para las operaciones de entrada/salida: una de bajo nivel, streambuf, que no se va a explicar porque sólo es utilizada por programadores expertos, y otra de alto nivel, con las clases: istream, ostream y iostream, que derivan de la clase ios. Estas clases disponen de variables y métodos para controlar los flujos de entrada y salida. La clase que se emplea normalmente para controlar el flujo de entrada/salida es iostream. A continuación se muestra la jerarquía de clases de entrada y salida de C++ donde las clases ifstream, ofstream y fstream se utilizan para el manejo de ficheros. - 99 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. En C++ se distinguen dos tipos de ficheros de cabecera: C y C++. Los de C no hacen uso de espacio de nombres y llevan el prefijo “c”. Por ejemplo, cstdio, cstdlib o cstring. Los ficheros de encabezado de C++, sin embargo, hacen uso de espacio de nombres (el espacio de nombres estándar std). En ambos casos, no llevan la extensión .h. Temporalmente, es posible que estén disponibles los ficheros de cabecera antiguos (con la extensión .h), pero no se aconseja su uso. Además, hay que tener cuidado para no confundir string.h (librería de C), cstring (librería de C adaptada para ser usada en C++) y string (librería de C++). Las librerías estándar de C++ están definidas dentro de un espacio de nombres llamado std. Por tanto, si se quiere evitar el tener que emplear el operador de ámbito (::) constantemente, hay que añadir la sentencia using namespace std; justo después de la inclusión (#include) de las librerías. Esta sentencia permite, por tanto, el acceso a todos los miembros definidos en el espacio de nombres std que se emplea en el fichero iostream. - 100 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 3.6. Ejemplo de aplicación orientada a objetos mediante MinGW Developer Studio. Una vez vistos los conceptos básicos para entender el desarrollo de una aplicación orientada a objetos en C++ se verá el ejemplo de la clase Persona desarrollado en MinGW Developer Studio. A continuación se muestra el contenido del fichero Persona.h que contiene la definición de la clase Persona. // Declaración de la Clase Persona #include<iostream> using namespace std; class Persona { private: // Atributos string nombre; int edad; public: //Getters string getNombre(void){return nombre;} int getEdad(void){return edad;} //Setters void setNombre(string _nombre){nombre=_nombre;} void setEdad(int _edad){edad=_edad;} //Constructor Persona(string _nombre, int _edad) { nombre=_nombre; edad=_edad; } }; Es preciso comentar que cuando se desarrollan aplicaciones orientadas a objetos es muy habitual declarar las diferentes clases con las que se va a - 101 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. trabajar en ficheros de cabecera independientes (extensión .h) y luego incluirlas en el programa principal por medio de la directiva #include. A continuación se muestra el programa principal (fichero programa.cpp) que incluye el fichero Persona.h mostrado anteriormente. // Programa principal #include<iostream> #include "Persona.h" // Inclusión del fichero donde se declara // la clase Persona using namespace std; int main(void) { Persona *p1; p1=new Persona("Pedro", 48); // Creación dinámica Persona p2("Ana", 35); // Creación automática cout<<"Persona 1 - Nombre: "<<p1->getNombre()<<" Edad: " <<p1->getEdad()<<endl; // Información del objeto dinámico p1 cout<<"Persona 2 - Nombre: "<<p2.getNombre()<<" Edad: " <<p2.getEdad()<<endl; // Información del objeto automático p2 } En el ejemplo que se muestra sobre estas líneas se crean dos objetos de clase Persona y se muestra su información. El primer objeto, p1, se crea de forma dinámica mediante el operador new tras haber sido declarado en la línea anterior. Hay que recordar que el objeto va precedido del operador asterisco (*) en su declaración. El segundo objeto, p2, es creado de forma automática por lo que la declaración y creación del objeto van en la misma línea de código. Posteriormente, mediante cout (se explicará en el siguiente apartado) se muestra la información de ambos objetos invocando a sus métodos correspondientes (getNombre para obtener el nombre y getEdad para obtener la - 102 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. edad). En el caso del objeto p1, creado de forma dinámica, se accede a sus métodos mediante una flecha según lo descrito en el apartado 3.3. Por último, se muestra la salida por pantalla tras la ejecución del código mostrado anteriormente: 3.7. Operadores de entrada/salida. En todo programa C++ existen dos elementos que permiten al usuario comunicarse con el programa. Se trata de la salida estándar, “cout” y de la entrada estándar “cin”. Estos elementos permiten enviar a la pantalla o leer desde el teclado cualquier variable o constante, incluidos literales. Equivale a las funciones printf y scanf propias del lenguaje de programación C y situadas en la librería stdio.h. cout es un objeto de la clase ostream y cin un objeto de la clase istream. Como ambas clases heredan de la clase superior iostream basta con incluir esta última clase al comienzo del programa para poder utilizar ambos objetos. El diagrama con la jerarquía de clases para efectuar entrada/salida en C++ se mostró anteriormente en el apartado 3.5. A continuación se muestra el formato de utilización de ambas clases: - 103 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. #include <iostream> using namespace std; cout << <variable|constante> [<< <variable|constante>...]; cin >> <variable> [>> <variable>...]; Su uso es muy simple tal y como se muestra en el siguiente ejemplo donde se lee un número por medio de cin y se muestra en pantalla por medio de cout: #include <iostream> using namespace std; int main() { int a; cin >> a; cout << "la variable a vale " << a; } Un método muy útil para cout es “endl”, que hará que la siguiente salida se imprima en una nueva línea. cout << “hola” << endl; Otro método, éste para “cin” es ”get()“, que sirve para leer un carácter, pero que nos puede servir para detener la ejecución de un programa. Esto es especialmente útil cuando se trabaja con compiladores que crean programas de consola win32 en los que se produce lo siguiente: cuando se ejecutan los programas desde el compilador con el que se esté trabajando, al terminar se cierra la ventana automáticamente, impidiendo ver los resultados. Usando get() se puede detener la ejecución del programa hasta que se pulse una tecla. Por otra parte, hay veces, sobre todo después de una lectura mediante cin, en las que pueden quedar caracteres pendientes de leer. En ese caso hay que usar más de una línea cin.get(). - 104 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 3.8. Modificadores. Las variables que se declaran en los programas desarrollados en lenguaje de programación C++ tienen el siguiente formato: [mod_general] [mod_almacenamiento] tipo identificador [=valor] [mod_general] [mod_almacenamiento] tipo identificador [(valor)] La diferencia entre ambos formatos reside en que la inicialización de una variable puede realizarse de forma convencional mediante el operador de asignación ‘=’ (primer caso) o bien situando el valor entre paréntesis (segundo caso). Los modificadores son opcionales y se sitúan antes del tipo de la variable a inicializar. Existen dos tipos de modificadores: modificadores generales y modificadores de almacenamiento. o Modificador general: Indica al compilador una variación en el comportamiento habitual de una variable. Si no aparece el compilador no asume ninguno por defecto. Existen los siguientes tipos: const: Constantes, se marcan como de solo lectura y no pueden modificarse durante el resto de la ejecución. Una variable definida como const se comporta como una constante (numérica o literal) en todo el programa y sólo se le puede asignar un valor inicial. Su ventaja principal frente a la directiva #define es que el compilador realiza una comprobación de tipos. Ejemplo: const int tamano=1; volatile: El valor de la variable se puede alterar por medios distintos al propio programa, por ejemplo una llamada del sistema operativo. Se usan en muy raras ocasiones. - 105 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. mutable: Aplicable a objetos, indica que un atributo puede cambiar su valor pese a ser constante (sólo lectura). Se usa raramente. o Modificador de almacenamiento: Indica el tipo de almacenamiento en memoria y el momento en que se crea y se destruye una variable. Existen los siguientes tipos: auto: Automático, no se usa. Es el modificador por defecto. register: La variable se almacena en un registro del procesador. Está obsoleto ya que los compiladores modernos optimizan por defecto la forma en que se deben almacenar las variables. Se mantiene por compatibilidad con códigos más antiguos. static: Cuando una variable es local indica al compilador que solo debe construirla una vez y debe hacer su valor perdurable para futuras ejecuciones del mismo bloque de código. Se suele utilizar sobre todo para limitar el acceso a algunas variables globales. extern: Se utiliza para declarar en el código propio variables globales que se corresponden con variables declaradas en otros módulos. - 106 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 3.9. Variable reservada this. this es una variable reservada de C++ que no necesita ser declarada. Esta variable es un puntero al objeto concreto al que se aplica el método que se está ejecutando. Es una variable predefinida para todos los métodos u operadores de una clase. Este puntero contiene la dirección del objeto concreto de la clase al que se está aplicando el método o el operador. Se puede decir que this es un alias del objeto correspondiente. Conviene tener en cuenta que cuando un método se aplica a un objeto de su clase (su argumento implícito), accede directamente a los atributos (sin utilizar el operador punto o flecha), pero no tiene forma de referirse al objeto como tal, pues no le ha sido pasado explícitamente como argumento. Este problema se resuelve con la variable reservada this. A continuación se muestra un ejemplo de empleo de dicha variable en la clase Persona: - 107 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. #include<iostream> using namespace std; class Persona { private: // Atributos string nombre; int edad; public: //Getters string getNombre(void){return nombre;} int getEdad(void){return edad;} //Setters void setNombre(string _nombre){nombre=_nombre;} void setEdad(int _edad){edad=_edad;} // Método que devuelve el año de nacimiento int devuelveFechaNac(void) { return 2008 – this->getEdad(); } //Constructor Persona(string _nombre, int _edad) { nombre=_nombre; edad=_edad; } }; En el ejemplo anterior se puede ver implementado el método devuelveFechaNac que devuelve la fecha de nacimiento de un objeto de clase Persona. Para realizar este cálculo se necesita conocer el valor del atributo edad por lo que se invoca el método getEdad gracias a la variable reservada this. - 108 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 3.10. Métodos inline. Los métodos inline se utilizan para mejorar la velocidad de ejecución. Un método marcado como inline indica al compilador que debe sustituir cada llamada a dicho método por su código correspondiente. De esta manera se mejora la velocidad de proceso ya que se ahorra las instrucciones de salto y devolución de valores al programa principal. La principal ventaja de un método inline es que mejora la eficiencia del programa sin afectar a su legibilidad. Los métodos cuyo código aparece dentro de la declaración de una clase son por defecto inline. Los métodos inline se usan cuando la implementación del método no es muy compleja como, por ejemplo, métodos que devuelven cálculos muy simples. A continuación se muestra un ejemplo de un método inline que calcula la longitud de una circunferencia a partir de su radio: inline double circun(double radio) int main(void) { { double r; return 2*3.1416*radio; cin >> r; } cout << “La longitud de la circunferencia cuyo radio es” << r << “es: ” << } circun(r); Se debe tener en cuenta que los compiladores analizan el código del método y deciden si usan el método como inline o como método normal. La decisión depende del compilador. Cuando un método se implementa dentro de la declaración de la clase, se considera como inline. A continuación se muestra un ejemplo de esta situación: - 109 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. #include<iostream> using namespace std; class MiClase { private: // Atributos int i; public: void print() { cout << i << ‘’; // Método inline implícito } }; 3.11. Clases y métodos friend. Existen ocasiones en las que dos clases están muy relacionadas entre sí de modo que se quiere que una tenga acceso a la otra y que trabajen conjuntamente con los mismos atributos a través de los métodos. Sin embargo, una de las limitaciones que presentan los métodos es que sólo pueden pertenecer a una única clase. Además, un método convencional sólo puede actuar directamente sobre un único objeto de la clase (su argumento implícito, que es el objeto con el que ha sido llamado por medio del operador punto (.) o flecha (->), como por ejemplo en per1.setEdad(45)). Para que actúe sobre un segundo o un tercer objeto hay que pasárselos como argumentos. Se puede concluir que a pesar de las grandes ventajas del encapsulamiento (se verá en el apartado 4.1 del capítulo 4), en muchas ocasiones es necesario dotar a la programación orientada a objetos de una mayor flexibilidad. Esto se consigue por medio de los métodos friend. Un método friend de una clase es un método que no pertenece a la clase, pero que tiene permiso para acceder a sus atributos y a sus métodos privados por medio de los operadores punto (.) y flecha (->), sin tener que recurrir a los - 110 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. métodos públicos de la clase. Si una clase se declara friend de otra, todos sus métodos son friend de esta segunda clase. El carácter de friend puede restringirse a métodos concretos, que pueden pertenecer a alguna clase o pueden ser métodos generales que no pertenecen a ninguna clase. Para declarar un método o una clase como friend de otra clase, es necesario hacerlo en la declaración de la clase que debe autorizar el acceso a sus atributos privados. Esto se puede hacer de forma indiferente en la zona de declaración de variables o en la zona privada de declaración de atributos. Un ejemplo de declaración de una clase friend podría ser el que sigue: class MiClase { friend class Amiga; private: int atributo; public: int getAtributo(){return atributo;} }; Es muy importante tener en cuenta que esta relación funciona sólo en una dirección, es decir, los métodos de la clase Amiga pueden acceder a los atributos privados de la clase MiClase a través de sus métodos, por ejemplo a la variable entera atributo a través del método getAtributo(), pero esto no es cierto en sentido inverso: los métodos de la clase MiClase no pueden acceder a un atributo privado de la clase Amiga a través de sus métodos. Si se quiere que varias clases tengan acceso mutuo a todos los atributos y métodos, cada una debe declararse como friend en todas las demás, para conseguir una relación recíproca. Se plantea un problema cuando dos clases deben ser declaradas mutuamente friend la una de la otra. Considérense por ejemplo las clases vector y matriz. Las declaraciones podrían ser las siguientes: - 111 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. // declaración de las clases vector y matriz (mutuamente friend) class matriz; // declaración anticipada de clase matriz class vector { // declaración de métodos de la clase vector ... friend matriz; }; class matriz { // declaración de métodos de la clase matriz ... friend vector; }; A primera vista sorprende la segunda línea de lo que sería el fichero de declaración de ambas clases. En esta línea aparece la sentencia class matriz;. Esto es lo que se llama una declaración anticipada, que es necesaria por el motivo que se explica a continuación. Sin declaración anticipada cuando la clase matriz aparece declarada como friend en la clase vector, el compilador aún no tiene noticia de dicha clase, cuya declaración viene después. Al no saber lo que es matriz, da un error. Si la clase matriz se declara antes que la clase vector, el problema se repite, pues vector se declara como friend en matriz. La única solución es esa declaración anticipada que advierte al compilador que matriz es una clase cuya declaración se encuentra más adelante. - 112 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 4 Paradigmas de programación - 113 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 4. Paradigmas de programación. Para explicar la POO (Programación Orientada a Objetos) es fundamental enumerar las características o paradigmas propios de este enfoque. En este capítulo se explicarán en detalle los cinco paradigmas más importantes de la POO: el encapsulamiento, la ocultación, la abstracción, la herencia y el polimorfismo. 4.1. Encapsulamiento. En programación orientada a objetos se denomina encapsulamiento a la ocultación del estado, es decir, de los datos (atributos) de un objeto de manera que sólo se pueden cambiar mediante las operaciones (métodos) definidas para ese objeto. Cada objeto está aislado del exterior, es un módulo natural, y la aplicación entera se reduce a un agregado o rompecabezas de objetos. El aislamiento protege a los datos asociados a un objeto contra su modificación por quien no tenga derecho a acceder a ellos, eliminando efectos secundarios e interacciones. De esta forma el usuario de la clase puede obviar la implementación de los métodos y propiedades para concentrarse sólo en cómo usarlos. Por otro lado se evita que el usuario pueda cambiar su estado de manera imprevista e incontrolada. Como se pudo observar en el diagrama del objeto de la clase Persona del capítulo 3 (figura), los atributos del objeto se localizan en el centro o núcleo del objeto. Los métodos rodean y esconden el núcleo del objeto de otros objetos en el programa. Al empaquetamiento de los atributos de un objeto con la protección de sus métodos se le llama encapsulamiento. - 114 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Típicamente, el encapsulamiento es utilizado para esconder detalles de implementación a otros objetos. Entonces, los detalles de implementación pueden cambiar en cualquier momento sin afectar a otras partes del programa. El encapsulamiento de atributos y métodos en un componente de software ordenado es una idea simple pero potente que provee dos principales beneficios a los desarrolladores de software: El encapsulamiento consiste en unir en la clase las características y comportamientos, esto es, los atributos y métodos. Es tener todo esto en una sola entidad. En los lenguajes estructurados esto era imposible. Es evidente que el encapsulamiento se logra gracias a la abstracción y la ocultación que se verán en los próximos apartados. La utilidad del encapsulamiento reside en la facilidad para manejar la complejidad, ya que se tendrá a las clases como cajas negras donde sólo se conoce el comportamiento pero no los detalles internos, y esto es conveniente porque lo que interesará al usuario será conocer qué hace la clase pero no será necesario saber cómo lo hace. El encapsulamiento da lugar a que las clases se dividan en dos partes: Interfaz: captura la visión externa de una clase, abarcando la abstracción del comportamiento común a los ejemplos de esa clase. La interfaz de un objeto ya se explicó al comienzo del capítulo 3. Implementación: comprende la representación de la abstracción, así como los mecanismos que conducen al comportamiento deseado. La forma habitual de poner en práctica el paradigma de encapsulamiento es mediante los especificadores de acceso explicados en el apartado 3.4 del capítulo 3. - 115 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 4.2. Ocultación. El paradigma de ocultación hace referencia a que los atributos privados de un objeto no pueden ser modificados ni obtenidos a no ser que se haga a través de los métodos públicos pertenecientes a su interfaz. Como ya se ha comentado anteriormente, los atributos de un objeto no son accesibles de manera directa sino que hay que pasar por los métodos para acceder a ellos. Esto se debe a que los atributos están ocultos mientras que los métodos forman parte de la interfaz del objeto, es decir, la parte visible por el resto de objetos. Precisamente es la interfaz la que materializa la definición de ocultación. Cada objeto está aislado del exterior, es un módulo natural, y cada tipo de objeto expone una interfaz a otros objetos que especifica cómo pueden interactuar con los objetos de la clase. El aislamiento protege a las propiedades de un objeto contra su modificación por quien no tenga derecho a acceder a ellas, solamente los propios métodos internos del objeto pueden acceder a su estado. Esto asegura que otros objetos no pueden cambiar el estado interno de un objeto de manera inesperada, eliminando efectos secundarios e interacciones inesperadas. Algunos lenguajes relajan esto, permitiendo un acceso directo a los datos internos del objeto de una manera controlada y limitando el grado de abstracción. La aplicación entera se reduce entonces a un agregado o rompecabezas de objetos. - 116 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 4.3. Abstracción. La abstracción expresa las características esenciales de un objeto, las cuales distinguen al objeto de los demás. Además de distinguir entre los objetos provee límites conceptuales. Entonces se puede decir que el encapsulamiento separa las características esenciales de las no esenciales dentro de un objeto. Si un objeto tiene más características de las necesarias resultará difícil de usar, modificar, construir y comprender. La abstracción genera una percepción de simplicidad dado que minimiza la cantidad de características que definen a un objeto. A la hora de realizar la abstracción de un elemento del mundo real se hace lo siguiente: se selecciona el elemento y se toma la parte que interesa, la parte representativa del objeto, omitiendo así algunas características de dicho elemento. Si el programador toma los atributos que le interesan, entonces se trata de una abstracción de datos. Si por el contrario toma los métodos que le interesan, entonces será una abstracción funcional. Cada objeto en el sistema sirve como modelo de un "agente" abstracto que puede realizar trabajo, informar y cambiar su estado, y "comunicarse" con otros objetos 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. Pensar en términos de objetos es muy parecido a cómo se haría en la vida real. Por ejemplo se va a pensar en un coche para tratar de modelarlo en un esquema de POO. Se podría decir que el coche es el elemento principal que tiene una serie de características, como podrían ser el color, el modelo o la marca. Además tiene una serie de funcionalidades asociadas, como pueden ser ponerse en marcha, parar o aparcar. - 117 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Pues en un esquema POO el coche sería el objeto, las características serían los atributos como el color o el modelo y los métodos serían las funcionalidades asociadas como ponerse en marcha o parar. Estos objetos se podrán utilizar en las aplicaciones, por ejemplo en un programa que gestione un taller de coches se utilizarán objetos coche. Las aplicaciones orientadas a objetos utilizan muchos objetos para realizar las acciones que se desean realizar y ellas mismas también son objetos. Es decir, el taller de coches será un objeto que utilizará objetos coche, herramienta, mecánico, recambios, etc. 4.4. Herencia. La mente humana clasifica los conceptos de acuerdo a dos dimensiones: pertenencia y variedad. Se puede decir que el Seat Ibiza es un tipo de coche (variedad o relación del tipo es un) y que una rueda es parte de un coche (pertenencia o relación del tipo tiene un). En C++ se puede resolver el problema de la pertenencia mediante las estructuras, que pueden ser todo lo complejas que se quiera. Pero con la herencia se consigue clasificar los tipos de datos (abstracciones) por variedad, acercando así un paso más la programación al modo de razonar humano. La herencia se define como la capacidad de definir jerarquías mediante la división de una clase en subclases. La herencia permite que una clase (y los objetos que pertenecen a ella) herede los métodos y atributos de su clase base. La herencia permite, por tanto, definir una clase modificando una o más clases ya existentes. Estas modificaciones consisten habitualmente en añadir nuevos miembros (atributos o métodos) a la clase que se está definiendo, aunque también se pueden redefinir atributos o métodos ya existentes. La clase base de la que se parte en este proceso recibe el nombre de superclase o clase padre, y la nueva clase que se obtiene se denomina subclase - 118 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o clase hija. Ésta a su vez puede ser superclase en un nuevo proceso de derivación, iniciando de esta manera una jerarquía de clases. De ordinario las superclases suelen ser más generales que las subclases. Esto es así porque a las subclases se les suele ir añadiendo características, en definitiva atributos y métodos que diferencian, concretan y particularizan. En algunos casos una clase no tiene otra utilidad que la de ser superclase para otras clases que hereden de ella. A este tipo de superclases, de las que no se declara ningún objeto, se les denomina superclases abstractas y su función es la de agrupar miembros comunes de otras clases que heredarán de ellas. Por ejemplo, se puede definir la clase vehículo para después derivar de ella coche, bicicleta, patinete, etc., pero todos los objetos que se declaren pertenecerán a alguna de estas últimas clases; no habrá vehículos que sean sólo vehículos. Las características comunes de estas clases (como un atributo que indique si está parado o en marcha, otro que indique su velocidad, el método de arrancar y el de frenar, etc.), pertenecerán a la superclase y las que sean particulares de alguna de ellas pertenecerán sólo a la subclase (por ejemplo el número de platos y piñones, que sólo tiene sentido para una bicicleta, o el método embragar que sólo se aplicará a los vehículos de motor con varias marchas). Este mecanismo de herencia presenta múltiples ventajas evidentes a primera vista, si bien la más importante y la que dota a la POO de gran potencia es la posibilidad de reutilizar código sin tener que escribirlo de nuevo. Esto es posible porque todas las subclases pueden utilizar el código de la superclase sin tener que volver a definirlo en cada una de ellas. Además, la reusabilidad permite desarrollar nuevas clases (clases hija) tomando como referencia clases ya existentes (clases padre). Otra gran ventaja de la herencia es la eliminación de redundancias ya que en la superclase se definen los métodos y atributos comunes a las subclases. Uno de los problemas que aparece con la herencia es el del control del acceso a los datos. ¿Puede un método de una subclase acceder a los atributos - 119 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. privados de su superclase? En principio una clase no puede acceder a los atributos privados de otra, pero podría ser muy conveniente que una subclase accediera a todos los atributos de su superclase. Para hacer posible esto, existe el especificador de acceso protected. Este especificador es privado para todas aquellas clases que no son subclases, pero público para una subclase de la clase en la que se ha definido el atributo como protected. A la hora de aplicar la herencia existen dos formas: o por especialización: la nueva clase especializa el comportamiento de la clase ya existente. A Especializa Nueva Clase En el ejemplo de herencia por especialización de la figura, Nueva Clase hereda de A y A es, por tanto, una especialización de NC (Nueva Clase). A será la superclase o clase padre mientras que NC será la subclase o clase hija. Como NC hereda de A se puede decir que NC es un A y que la subclase (NC) tendrá los mismos métodos y atributos que la superclase (A) así como lo que la subclase NC refinará para generalizar el comportamiento. - 120 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o por generalización: la nueva clase generaliza el concepto de la clase ya existente. Nueva Clase Generaliza A En el ejemplo de herencia por generalización de la figura, Nueva Clase es una generalización de A. NC tendrá, por tanto, los mismos métodos y atributos de A así como aquellos que hayan sido implementados para llevar a cabo dicha generalización. Para entender estos conceptos de forma más clara se explicará un ejemplo del mundo real. Si se piensa en dos conceptos como son Trabajador y Persona se llega a las siguientes conclusiones: o Trabajador es un refinamiento de Persona o Trabajador especializa a Persona Se puede decir entonces que Trabajador es una Persona. A continuación se muestra el código de este mismo ejemplo programado en C++ en MinGW Developer Studio. - 121 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Clase Persona (fichero Persona.h) // Declaración de la Superclase Persona #include<iostream> using namespace std; class Persona { protected: // Atributos string nombre; int edad; public: //Getters string getNombre(void){return nombre;} int getEdad(void){return edad;} //Setters void setNombre(string _nombre){nombre=_nombre;} void setEdad(int _edad){edad=_edad;} //Constructor Persona(string _nombre, int _edad) { nombre=_nombre; edad=_edad; } }; Antes de mostrar la clase Trabajador, que hereda de la clase Persona, es preciso mostrar la sintaxis para llevar a cabo la herencia: class A {…}; // Clase padre o superclase class B : public A {…}; // Clase hija o subclase - 122 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Clase Trabajador (fichero Trabajador.h) // Declaración de la Subclase Trabajador #include<iostream> using namespace std; class Trabajador : public Persona // Trabajador subclase de Persona { private: // Atributos long sueldo; string departamento; public: //Getters long getSueldo(void){return sueldo;} string getDepartamento(void){return departamento;} //Setters void setSueldo(long _sueldo){sueldo=_sueldo;} void setDepartamento (string _departamento) {departamento=_departamento;} //Constructor Trabajador(string _nombre, int _edad, long _sueldo, string _departamento) : Persona(_nombre, _edad) { sueldo=_sueldo; departamento=_departamento; } }; A continuación se muestra el programa principal en el que se crea un objeto de clase Trabajador y se muestra su información: - 123 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Programa principal (fichero programa.cpp) #include<iostream> // Se incluyen los ficheros donde se definen las clases #include "Persona.h" #include "Trabajador.h" using namespace std; int main(void) { Trabajador *t1; t1 = new Trabajador("Antonio", 54, 2500, "Finanzas"); cout<<endl<<"Trabajador 1 - Nombre: "<<t1->getNombre() <<" Edad: "<<t1->getEdad()<<" Sueldo: " <<t1->getSueldo()<<" Departamento: " <<t1->getDepartamento()<<endl; } Explicación del ejemplo de herencia Trabajador-Persona o Persona.h: La superclase Persona es la misma que se mostró en el apartado 3.6 del capítulo 3 exceptuando una modificación que se realizó en el especificador de acceso de los atributos. El especificador pasó de ser public a ser protected para permitir a la subclase (Trabajador) acceder a sus atributos. Este especificador es privado para todas aquellas clases que no son subclases de la clase Persona. o Trabajador.h: La subclase Trabajador hereda de la clase Persona por lo que en su definición se especifica esta situación mediante la sentencia class Trabajador : public Persona. La clase Trabajador tendrá, por tanto, los mismos métodos y atributos que la clase Persona, su superclase. Además, tiene dos atributos adicionales como son el sueldo y el departamento en el que trabaja. Estos atributos son accedidos por medio de los getters y setters que también se definen en la clase - 124 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Trabajador. Por último, el constructor tendrá como parámetros sus atributos así como los de la superclase y se invocará el constructor de la superclase mediante una llamada directa por medio de la sentencia Trabajador(string string _nombre, _departamento) : int _edad, long Persona(_nombre, _sueldo, _edad) que permitirá crear un objeto de la clase Trabajador sin necesidad de reescribir el código necesario para definir los atributos de la superclase. El constructor de la clase padre es invocado siempre (de forma directa o indirectamente) antes de la ejecución del constructor de la subclase. o Programa.cpp: El programa principal necesita conocer la definición de la clase Persona y de su subclase Trabajador. Es por ello que es necesario incluir mediante la directiva #include los dos ficheros de cabecera donde se definen ambas clases. En el programa se crea un objeto de la clase Trabajador con un nombre, una edad, un sueldo y un departamento en el que trabaja. Hay que recordar que aunque nombre y edad son atributos de la clase Persona, la clase Trabajador hereda de ésta por lo que dichos atributos también pertenecerán a la subclase. Una vez creado el objeto t1 de clase Trabajador se muestra su información invocando los métodos correspondientes. A continuación se muestra la salida por pantalla tras la ejecución del código mostrado anteriormente: - 125 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Ahora se mostrará un diagrama del ejemplo anterior donde se visualizará de manera clara el funcionamiento de la herencia. Como se puede observar en la figura, la subclase Trabajador hereda los atributos y métodos de la superclase Persona. Además, define dos atributos y sus correspondientes métodos que refinan y especializan a la clase Persona. Estos atributos y métodos aparecen subrayados en color rojo en la figura. El constructor de Trabajador tendrá por parámetros los atributos heredados de Persona así como los definidos en la propia clase. - 126 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 4.4.1. Herencia múltiple. Hasta ahora se ha explicado la herencia simple, donde una clase sólo puede heredar de una superclase. Pues bien, la herencia múltiple permite que una clase pueda heredar comportamientos y características de más de una superclase. La herencia múltiple permite a una clase tomar funcionalidades de otras clases, como permitir a una clase llamada Hidroplano heredar de una clase llamada Aeroplano y una clase llamada Barco. La sintaxis necesaria para llevar a cabo la herencia múltiple en C++ se muestra a continuación: class Aeroplano {…}; class Barco {…}; class Hidroplano : public Aeroplano, public Barco {…}; En la herencia múltiple aparecen ambigüedades, por lo que debe usarse con cuidado ya que pueden presentarse problemas como los siguientes: o Una misma clase no debe especificarse dos o más veces como superclase de una dada. Este hecho puede producirse indirectamente como en el caso: class A {…}; class B : public A {…}; class C : public A {…}; class D : public B, public C {…}; - 127 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Una clase no puede heredar un mismo atributo o método de dos superclases. Cada lenguaje de programación trata estos problemas de herencia múltiple de forma diferente. En el caso de C++, el lenguaje requiere que el programador establezca de qué clase padre vendrá la característica a usar por medio del operador :: tal y como se muestra a continuación: Subclase :: Superclase.nombre_Atributo Subclase :: Superclase.nombre_Método 4.5. Polimorfismo. Se entiende por polimorfismo la capacidad de definir métodos distintos, que comparten el mismo nombre, pero que se aplican a clases diferentes. Estos métodos pueden actuar sobre objetos distintos dentro de una jerarquía de clases, sin tener que especificar el tipo exacto de los objetos. Esto se puede entender mejor con el siguiente ejemplo: Clase Triángulo + Pintar() Clase Cuadrado + Pintar() En el ejemplo que se ve en la figura se observa una jerarquía de clases. En los dos niveles de esta jerarquía está contenido un método llamado Pintar(). Este método no tiene por qué ser igual en todas las clases, aunque es habitual - 128 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. que sea un método que efectúe una operación muy parecida sobre distintos tipos de objetos. Es importante comprender que el compilador no decide en tiempo de compilación cuál será el método que se debe utilizar en un momento dado del programa. Esa decisión se toma en tiempo de ejecución. A este proceso de decisión en tiempo de ejecución se le denomina vinculación dinámica, en oposición a la habitual vinculación estática, consistente en decidir en tiempo de compilación qué método se aplica en cada caso. A este tipo de métodos, incluidos en varios niveles de una jerarquía de clases con el mismo nombre pero con distinta definición se les denomina métodos virtuales. Hay que insistir en que la definición del método en cada nivel es distinta. El polimorfismo hace posible que un usuario pueda añadir nuevas clases a una jerarquía sin modificar o recompilar el código original. Esto quiere decir que si desea añadir una nueva subclase es suficiente con establecer la clase padre, definir sus atributos y métodos, y compilar esta parte del código, ensamblándolo después con lo que ya estaba compilado previamente. Es necesario comentar que los métodos virtuales son algo menos eficientes que los métodos normales. A continuación se explica, sin entrar en gran detalle, el funcionamiento de los métodos virtuales. Cada clase que utiliza métodos virtuales tiene un vector de punteros, uno por cada método virtual, llamado v-table. Cada uno de los punteros contenidos en ese vector apunta al método virtual apropiado para esa clase, que será, habitualmente, el método virtual definido en la propia clase. En el caso de que en esa clase no esté definido el método virtual en cuestión, el puntero de v-table apuntará al método virtual de su clase padre más próxima en la jerarquía, que tenga una definición propia del método virtual. Esto quiere decir que buscará primero en la propia - 129 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. clase, luego en la clase anterior en el orden jerárquico y se irá subiendo en ese orden hasta dar con una clase que tenga definido el método buscado. Cada objeto creado de una clase que tenga un método virtual contiene un puntero oculto a la v-table de su clase. Mediante ese puntero accede a su vtable correspondiente y a través de esta tabla accede a la definición adecuada del método virtual. Es este trabajo extra el que hace que los métodos virtuales sean menos eficientes que los métodos normales. Como ejemplo se puede suponer la clase Trabajador y la clase Mecanico. Ambas tienen el método calcularSueldo() pero con la siguiente diferencia: o Trabajador: el sueldo se calcula como el número de horas trabajadas multiplicado por 6. o Mecanico: el sueldo se calcula como el número de horas trabajadas multiplicado por 20. Además, se añade un extra de 100€ por cada reparación que realice en el plazo de reparación establecido. El código correspondiente a los métodos explicados sería el siguiente: // método virtual de la clase Trabajador virtual void calcularSueldo() { //El método getNumhoras() devuelve el número de horas trabajadas sueldo=this.getNumhoras()*6; } // método virtual de la clase Mecanico virtual void calcularSueldo() { //El método getNumhoras() devuelve el número de horas trabajadas //El método getNumrep() devuelve el número de reparaciones //realizadas dentro del plazo establecido sueldo=this.getNumhoras()*20 + this.getNumrep()*100; } - 130 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. La idea central del polimorfismo es la de poder llamar a métodos distintos aunque tengan el mismo nombre, según la clase a la que pertenece el objeto al que se aplican. Esto es imposible utilizando nombres de objetos: siempre se aplica el método de la clase correspondiente al nombre del objeto y esto se decide en tiempo de compilación. Sin embargo, utilizando punteros puede conseguirse el objetivo buscado. Recuérdese que un puntero a la clase padre puede contener direcciones de objetos de cualquiera de las subclases. En principio, el tipo de puntero determina también el método que es llamado, pero si se utilizan métodos virtuales es el tipo de objeto al que apunta el puntero lo que determina el método que se llama. Esta es la esencia del polimorfismo. 4.5.1. Implementación de los métodos virtuales. Un método virtual puede ser llamado como un método convencional, es decir, utilizando vinculación estática. En este caso no se están aprovechando las características de los métodos virtuales, pero el programa puede funcionar correctamente. A continuación se presenta un ejemplo de este tipo de implementación que no es recomendable usar, ya que utilizando un método convencional se ganaría en eficiencia: Clase_A Objeto_1; // Se definen un objeto de una clase Clase_A *Puntero_1; // y un puntero que puede apuntarlo float atributo; Puntero_1 = &Objeto_1; atributo = Objeto_1.metodo_1(); //Utilización de vinculación estática atributo = Puntero_1->metodo_1();//Con métodos virtuales. Absurdo En el ejemplo anterior en las dos asignaciones a la variable atributo, los métodos que se van a utilizar se determinan en tiempo de compilación. - 131 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. A continuación se presenta un ejemplo de utilización correcta de los métodos virtuales: Clase_Padre Objeto_Padre; Clase_Hija Objeto_Hijo; Clase_Padre *Puntero_Padre_1; Clase_Padre *Puntero_Padre_2; float atributo; ... // El puntero a la clase padre puede apuntar a un objeto de la clase // padre Puntero_Padre_1 = &Objeto_Padre; // o a un objeto de la clase hija Puntero_Padre_2 = &Objeto_Hijo; ... // Utilización correcta de un método virtual atributo = Puntero_Padre_2->metodo_1(); En este nuevo ejemplo se utiliza vinculación dinámica, ya que el Puntero_Padre_2 puede apuntar a un objeto de la clase padre o a un objeto de cualquiera de las clases hija en el momento de la asignación a la variable atributo, en la última línea del ejemplo. Por eso, es necesariamente en tiempo de ejecución cuando el programa decide cuál es el metodo_1 concreto que tiene que utilizar. Ese metodo_1 será el definido para la clase del Objeto_Hijo si está definido, o la de la clase padre más próxima en el orden jerárquico que tenga definido ese metodo_1. - 132 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 4.5.2. Métodos virtuales puros. Habitualmente los métodos virtuales de la clase padre de la jerarquía no se utilizan porque en la mayoría de los casos no se declaran objetos de esa clase, y/o porque todas las subclases tienen su propia definición del método virtual. Sin embargo, incluso en el caso de que el método virtual de la clase padre no vaya a ser utilizado, debe declararse. De todos modos, si el método no va a ser utilizado es necesario definirlo, y es suficiente con declararlo como método virtual puro. Un método virtual puro se declara así: Virtual metodo_1()=0; // Método virtual puro La única utilidad de esta declaración es la de posibilitar la definición de métodos virtuales en las subclases. De alguna manera se puede decir que la definición de un método como virtual puro hace necesaria la definición de ese método en las subclases, a la vez que imposibilita su utilización con objetos de la superclase. Al definir un método virtual se debe tener en cuenta que: o No hace falta definir el código de ese método en la superclase. o No se pueden definir objetos de la superclase, ya que no se puede llamar a los métodos virtuales puros. o Sin embargo, es posible definir punteros a la superclase, pues es a través de ellos como será posible manejar objetos de las subclases. - 133 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 4.5.3. Clases abstractas. Se denomina clase abstracta a aquella que contiene uno o más métodos virtuales puros. El nombre se debe a que no puede existir ningún objeto de esa clase. Si una subclase no redefine un método virtual, la subclase la hereda como método virtual puro y se convierte también en clase abstracta. Por el contrario, aquellas subclases que redefinen todos los métodos virtuales puros de sus superclases reciben el nombre de subclases concretas, nomenclatura únicamente utilizada para diferenciarlas de las mencionadas anteriormente. Aparentemente puede parecer que carece de sentido definir una clase de la que no va a existir ningún objeto, pero se puede afirmar, sin miedo a equivocarse, que la abstracción es una herramienta imprescindible para un correcto diseño de la Programación Orientada a Objetos. Es evidente que la jerarquía que se presenta en la figura sobre estas líneas no es suficiente, porque un avión y un helicóptero, o un patinete y una bicicleta, serían objetos de la misma clase. Pero lo que se pretende ilustrar es la necesidad de una clase Vehículo que englobe las características comunes de todos ellos (dimensiones, peso, velocidad máxima,…) aunque no exista ningún objeto de esa clase, ya que cualquier vehículo en el que se piense, podrá definirse como un objeto de una subclase de la primera superclase. - 134 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Habitualmente las clases superiores de muchas jerarquías de clases son clases abstractas y las clases que heredan de ellas definen sus propios métodos virtuales, convirtiéndose así en clases concretas. 4.5.4. Destructores virtuales. Como norma general, el constructor de la superclase se llama antes que el constructor de la subclase. Con los destructores, sin embargo, sucede al revés: el destructor de la subclase se llama antes que el de la superclase. Por esa razón, en el caso de que se borre, aplicando delete, un puntero a un objeto de la superclase que apunte a un objeto de una subclase, se llamará al destructor de la superclase, en vez de al destructor de la subclase, que sería lo adecuado. La solución a este problema consiste en declarar como virtual el destructor de la superclase. Esto hace que automáticamente los destructores de las subclases sean también virtuales, a pesar de tener nombres distintos. De este modo, al aplicar delete a un puntero de la superclase que puede apuntar a un puntero de ese tipo o a cualquier objeto de una subclase, se aplica el destructor adecuado en cada caso. Por eso es conveniente declarar un destructor virtual en todas las clases abstractas, ya que aunque no sea necesario para esa clase, sí puede serlo para una clase que herede de ella. Este problema no se presenta con los constructores y por eso no existe ningún tipo de constructor virtual o similar. - 135 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. PARTE III: Estudio de las librerías gráficas del compilador para permitir desarrollar desarrollar interfaces gráfica gráficas de usuario (GUI) - 136 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 1 Introducción - 137 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 1. Introducción. La interacción entre las personas y los ordenadores en la actualidad se realiza principalmente a través de interfaces gráficas de usuario (Graphical User Interfaces - GUI), un tipo de interfaz de usuario compuesto por metáforas gráficas inscritas en una superficie de contacto. Esta superficie contiene además otros elementos como los iconos, botones, controles, etc. e interfaces humanos (dispositivos de entrada como el ratón o el teclado) necesarios para posibilitar dicha interacción con los signos-objetos en la interfaz gráfica. El concepto de interfaz de usuario es un concepto amplio que se utiliza para referirse de forma genérica al espacio que media la relación de un sujeto y un ordenador o sistema interactivo. El interfaz de usuario es esa “ventana mágica” de un sistema informático que posibilita a una persona interactuar con él. Cuando se habla de interfaz gráfica de usuario, el concepto es aún más específico en cuanto que supone un tipo específico de interfaz que usa metáforas visuales y signos gráficos como paradigma interactivo entre la persona y el ordenador. La interfaz gráfica de usuario se define, pues, como “un método de interacción con un ordenador a través del paradigma de manipulación directa de imágenes gráficas, controles y texto”. En el contexto del proceso de interacción persona-ordenador, la interfaz gráfica de usuario es el artefacto tecnológico de un sistema interactivo que posibilita, a través del uso y la representación del lenguaje visual, una interacción amigable con un sistema informático. La interfaz gráfica de usuario es un tipo de interfaz de usuario que utiliza un conjunto de imágenes y objetos gráficos para representar la información y acciones disponibles en la interfaz. Habitualmente las acciones se realizan mediante manipulación directa para facilitar la interacción del usuario con el ordenador. - 138 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Las interfaces gráficas de usuario surgen como evolución de la línea de comandos de los primeros sistemas operativos y son pieza fundamental en un entorno gráfico. Como ejemplo de interfaces gráficas de usuario se pueden citar el escritorio o desktop del sistema operativo Windows, el entorno X-Window de Linux o el entorno Finder de Mac OS X. La historia reciente de la informática está indisolublemente unida a las interfaces gráficas, puesto que los sistemas operativos gráficos han ocasionado grandes consecuencias en la industria del software y del hardware. Las interfaces gráficas surgen de la necesidad de hacer los ordenadores más accesibles para el uso de los usuarios comunes. La mayoría de ordenadores domésticos requerían conocimientos de BASIC (el 95% de ellos mostraban el intérprete BASIC al encenderse) u ofrecían una interfaz de línea de órdenes (como los sistemas operativos CP/M o los diferentes OS del Apple II), lo que requería conocimientos por encima de la media si se deseaba hacer algo más que usarlo como consola de videojuegos. Esta limitación fue salvada gracias al desarrollo de los entornos gráficos, que permitieron que las personas pudieran acceder a un ordenador sin tener que pasar por el tortuoso proceso de tener que aprender a manejar un entorno bajo línea de órdenes. - 139 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 2 API de Windows (WinAPI) - 140 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 2. API de Windows. A la hora de programar interfaces gráficas de usuario (GUI) mediante MinGW Developer Studio se emplea el API (Application Programs Interface) de Windows, también conocido como WinAPI. 2.1. Introducción. El API de Windows, WinAPI, es un conjunto de interfaces de programación de aplicaciones (application programming interfaces - API) de Microsoft disponible en los sistemas operativos Microsoft Windows. Todos los programas Windows deben interactuar con el API de Windows sin importar el lenguaje de programación. La Windows Driver Foundation o API Nativa (Native API), utilizada principalmente por drivers de dispositivo, proporciona acceso de bajo nivel a sistemas Windows. El API de Windows está formado por más de 600 funciones en lenguaje de programación C. Para acceder a ella los compiladores utilizan librerías de objetos, permitiendo acceder al API de manera más rápida y sencilla. La librería de MinGW Developer Studio que permite dicho acceso es windows.h. Hasta 1985, los ordenadores empleaban el sistema operativo MS-DOS. Este sistema operativo funcionaba a base de interrupciones de tal modo que cada vez que un programa necesitaba hacer algo, llamaba a una interrupción, servicio de BIOS o de DOS. Sin embargo, en Agosto de 1985 apareció en el mercado la primera versión de Windows que disponía de interfaz gráfica de usuario y con ella se produjo un cambio radical. Este cambio se basa en que en Windows es el propio sistema operativo el que llama al programa por medio de mensajes cada vez que se mueve el ratón, se pulsa una tecla del teclado o se produce lo que se conoce como evento. Cuando esto sucede, el sistema operativo avisa al programa del cambio (evento) por medio de un mensaje y éste - 141 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. decide si quiere llamar a una interrupción que lo controle. En caso de llamar a una interrupción de DOS se hará por medio del API de Windows. En Windows se dispone de un kit de desarrollo software (software development kit - SDK) que proporciona documentación y herramientas para permitir a los desarrolladores crear software usando el API de Windows y las tecnologías asociadas a Windows. La funcionalidad que proporciona el API de Windows se puede agrupar en ocho categorías: o Servicios Básicos (Base Services) o Servicios Avanzados (Advanced Services) o Interfaz de Gráficos de Dispositivos (Graphics Device Interface) o User Interface (Interfaz de Usuario) o Librería Común de Cuadro de Diálogo (Common Dialog Box Library) o Librería Común de Control (Common Control Library) o Shell de Windows (Windows Shell) o Servicios de Red (Network Services) La categoría en la que se profundizará será la de Interfaz de Usuario (User Interface) ya que es la que proporciona la funcionalidad para crear y gestionar ventanas y controles básicos como botones y cajas de texto, recibir eventos del ratón y el teclado, y otra funcionalidad asociada con la parte GUI de Windows. Esta unidad funcional reside en el fichero user.exe en Windows de 16 bits y en el fichero user32.dll en Windows de 32 bits. Desde la primera versión de Windows XP, los controles básicos residen en el fichero comctl32.dll, junto con los controles básicos (Common Control Library). - 142 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 2.2. Características de la programación en Windows. A la hora de explicar la forma en que se programan las interfaces gráficas de usuario en Windows usando el API es preciso explicar una serie de características especiales de la programación en Windows como son la independencia, los recursos, las ventanas, los eventos y los controles. 2.2.1. Independencia de la máquina. Los programas Windows son independientes de la máquina en la que se ejecutan (o al menos deberían serlo), el acceso a los dispositivos físicos se hace a través de interfaces, y nunca se accede directamente a ellos. Esta es una de las principales ventajas para el programador, que no tiene que preocuparse por el modelo de tarjeta gráfica o de impresora que emplea puesto que la aplicación funcionará con todas, y será el sistema operativo el que se encargue de que así sea. 2.2.2. Recursos. Un concepto importante es el de recurso. Desde el punto de vista de Windows, un recurso es todo aquello que puede ser usado por una o varias aplicaciones. Existen recursos físicos, que son los dispositivos que componen el ordenador, como la memoria, la impresora, el teclado o el ratón y recursos virtuales o lógicos, como los gráficos, los iconos o las cadenas de caracteres. Por ejemplo, si una aplicación requiere el uso de un puerto serie, primero debe averiguar si está disponible, es decir, si existe y si no lo está usando otra aplicación; y después lo reservará para su uso. Esto es necesario porque este tipo de recurso no puede ser compartido. Lo mismo pasa con la memoria o con la tarjeta de sonido, aunque son casos diferentes. Por ejemplo, la memoria puede ser compartida, pero de una - 143 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. forma general, cada porción de memoria no puede compartirse y se trata de un recurso finito. Las tarjetas de sonido, dependiendo del modelo, podrán o no compartirse por varias aplicaciones. Otros recursos como el ratón y el teclado también se comparten, pero se asigna su uso automáticamente a la aplicación activa, que normalmente se conoce como la que tiene el "foco", es decir, la que mantiene contacto con el usuario. Desde el punto de vista del programador de aplicaciones, también se consideran como recursos varios componentes como los menús, los iconos, los cuadros de diálogo, las cadenas de caracteres, los mapas de bits, los cursores, etc. En los programas, Windows almacena separados el código y los recursos, dentro del mismo fichero, y estos últimos pueden ser editados por separado, permitiendo por ejemplo, hacer versiones de los programas en distintos idiomas sin tener acceso a los ficheros fuente de la aplicación. 2.2.3. Ventanas. La forma en que se presentan las aplicaciones Windows (al menos las interactivas) ante el usuario, es la ventana. Una ventana es un área rectangular de la pantalla que se usa de interfaz entre la aplicación y el usuario. Cada aplicación tiene al menos una ventana, la ventana principal, y todas las comunicaciones entre usuario y aplicación se canalizan a través de una ventana. Cada ventana comparte el espacio de la pantalla con otras ventanas, incluso de otras aplicaciones, aunque sólo una puede estar activa, es decir, sólo una puede recibir información del usuario. 2.2.4. Eventos. Los programas en Windows están orientados a eventos, es decir, normalmente están esperando a que se produzca un acontecimiento que les incumba, y mientras tanto permanecen dormidos. - 144 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Un evento puede ser, por ejemplo, el movimiento del ratón, la activación de un menú, la llegada de información desde el puerto serie, una pulsación de una tecla, etc. Esto se debe a que Windows es un sistema operativo multitarea, y el tiempo del microprocesador ha de repartirse entre todos los programas que se estén ejecutando. Si los programas fueran secuenciales puros, esto no sería posible, ya que hasta que una aplicación finalizara, el sistema no podría atender al resto. Ejemplo de programa secuencial: - 145 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Ejemplo de programa por eventos: 2.2.5. Controles. Los controles son la forma en que las aplicaciones Windows intercambian datos con el usuario. Normalmente se usan dentro de los cuadros de diálogo, pero en realidad pueden usarse en cualquier ventana. Los más importantes y conocidos son: o control static: son etiquetas, marcos, iconos o dibujos. o control edit: permiten que el usuario introduzca datos alfanuméricos en la aplicación. o control list box: el usuario puede escoger entre varias opciones de una lista. o control combo box: es una combinación entre un edit y un list box. o control scroll bar: barras de desplazamiento, para la introducción de valores entre márgenes definidos. - 146 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o control button: realizan acciones o comandos. Del control button derivan otros dos controles muy comunes: control check box: permite leer variables de dos estados "checked" o "unchecked". control radio button: se usa en grupos. Dentro de cada grupo sólo uno puede ser activado. 2.3. Creación de proyectos WinAPI en MinGW Developer Studio. Inicialmente, el área de trabajo del entorno de desarrollo está vacía. Para crear ahora la estructura de una nueva aplicación WinAPI, se procede del siguiente modo: a. Se elige la opción New en el menú File (o se pulsan las teclas Ctrl y N simultáneamente) o bien se pulsa el botón herramientas. - 147 - de la barra de Programación Orientada a Objetos en C mediante MinGW Developer Studio. b. A continuación, se presenta una ventana en la que se puede elegir el tipo de aplicación que se desea crear. Se selecciona la pestaña Projects y la aplicación de tipo Win32 Application. Ahora se procede a nombrar el proyecto escribiendo el nombre que se desea en el cuadro Project name. En el cuadro Location se permite especificar la ruta de acceso al directorio, es decir, el directorio donde se creará la carpeta de nombre igual al del proyecto y que contendrá todos los ficheros relativos al proyecto (ejecutables, código fuente, etc.). Una vez especificado el nombre del proyecto y la ruta de acceso se confirma el cuadro de diálogo pulsando OK y ya se ha creado un proyecto nuevo. En el directorio especificado en el cuadro Location se habrá creado un fichero llamado nombre_del_proyecto.msp/mdsp (MinGWStudio Project Files). c. El paso siguiente es crear un fichero y añadirlo al proyecto actualmente vacío. Se elige la opción New del menú File (o se pulsan las teclas Ctrl y N simultáneamente) o se pulsa el botón de la barra de herramientas. Se selecciona la pestaña Files y el fichero de tipo C/C++ Source File para crear un fichero de lenguaje de programación C (*.c) que contenga el código fuente. Se nombra el fichero (se debe añadir la extensión .c) en el cuadro File name y se confirma pulsando OK. El campo Location no debe ser modificado ya que por defecto se muestra la ruta de acceso al directorio del proyecto creado anteriormente. Además, la checkbox Add to project se encuentra activada para añadir el fichero al proyecto que se - 148 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. había creado previamente. Por tanto, la ruta de acceso y la checkbox no deben ser modificadas. En el directorio del proyecto se habrá creado un fichero llamado nombre_del_fichero.c (C Source File). d. El entorno ya está listo para introducir el código en la zona de edición. - 149 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 2.4. Componentes de una ventana. En este apartado se verán los elementos que componen una ventana, si bien no todos tienen por qué estar presentes en todas las ventanas. 1) El borde de la ventana: hay varios tipos, dependiendo de que estén o no activas las opciones de cambiar el tamaño de la ventana. Se trata de un área estrecha alrededor de la ventana que permite cambiar su tamaño. 2) Barra de título: zona en la parte superior de la ventana que contiene el icono y el título de la ventana. Esta zona también se usa para mover la ventana a través de la pantalla, y mediante doble clic, para cambiar entre el modo maximizado y el tamaño normal. 3) Caja de minimizar: pequeña área cuadrada situada en la parte derecha de la barra de título que sirve para disminuir el tamaño de la ventana. Antes de la aparición de Windows 95 la ventana se convertía a su forma icónica, pero desde la aparición de Windows 95 los iconos desaparecieron, la ventana se oculta y sólo permanece un botón en la barra de estado. 4) Caja de maximizar: pequeña área cuadrada situada en la parte derecha de la barra de título que sirve para agrandar la ventana para que ocupe toda la pantalla. Cuando la ventana está maximizada, se sustituye por la caja de restaurar. - 150 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 5) Caja de cerrar: pequeña área cuadrada situada en la parte derecha de la barra de título que sirve para cerrar la ventana. 6) Caja de control de menú: pequeña área cuadrada situada en la parte izquierda de la barra de título que normalmente contiene el icono de la ventana, y sirve para desplegar el menú del sistema. Menú (o menú del sistema): se trata de una ventana especial que contiene las funciones comunes a todas las ventanas, también accesibles desde las cajas y el borde, como minimizar, restaurar, maximizar, mover, cambiar tamaño y cerrar. Este menú se despliega al pulsar sobre la caja de control de menú. 7) Barra de menú: zona situada debajo de la barra de título que contiene los menús de la aplicación. 8) Barra de scroll horizontal: barra situada en la parte inferior de la ventana que permite desplazar horizontalmente la vista del área del cliente. 9) Barra de scroll vertical: barra situada en la parte derecha de la ventana que permite desplazar verticalmente la vista del área de cliente. 10) Área de cliente: es la zona donde el programador sitúa los controles y los datos para el usuario. En general es toda la superficie de la ventana que no está ocupada por las zonas anteriormente descritas. - 151 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 2.5. Notación húngara. La notación húngara es un sistema usado normalmente para crear los nombres de variables, tipos y estructuras cuando se programa en Windows. Es el sistema usado en la programación del sistema operativo, y también por la mayoría de los programadores. Fundamentalmente ayudará a interpretar el tipo básico al que pertenece cada estructura, miembro o tipo definido. Consiste en prefijos en minúsculas que se añaden a los nombres de las variables, y que indican su tipo; en el caso de tipos definidos, las letras del prefijo estarán en mayúscula. El resto del nombre indica la función que realiza la variable o tipo. A continuación se muestra una tabla con el significado de los prefijos más utilizados en notación húngara: Prefijo Significado b Booleano c Carácter (un byte) dw Entero largo de 32 bits sin signo (DOBLE WORD) f Flags empaquetados en un entero de 16 bits h Manipulador de 16 bits (HANDLE) l Entero largo de 32 bits lp Puntero a entero largo de 32 bits lpfn Puntero largo a una función que devuelve un entero lpsz Puntero largo a una cadena terminada con cero n Entero de 16 bits p Puntero a entero de 16 bits pt Coordenadas (x, y) empaquetadas en un entero de 32 bits rgb Valor de color RGB empaquetado en un entero de 32 bits sz Cadena terminada en cero u Sin signo (unsigned) w Entero corto de 16 bits sin signo (WORD) - 152 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Por último se muestran una serie de ejemplos de variables creadas con notación húngara así como ejemplos de tipos definidos por el API de Windows: o nContador: la variable es un entero que se usará como contador. o szNombre: una cadena terminada con cero que almacena un nombre. o bRespuesta: una variable booleana que almacena una respuesta. Ejemplos de tipos definidos por el API de Windows: o UINT: entero sin signo. Windows redefine los enteros para asegurar que el tamaño en bits es siempre el mismo para todas las variables del API. o LRESULT: entero largo usado como valor de retorno. o WPARAM: entero corto de 16 bits usado como parámetro. o LPARAM: entero largo de 32 bits usado como parámetro. o LPSTR: puntero largo a una cadena de caracteres. En el API de 32 bits no existen distinciones entre punteros largos y cortos, pero la nomenclatura se conserva por compatibilidad. o LPCREATESTRUCT: puntero a una estructura CREATESTRUCT, que define los parámetros de inicialización pasados al procedimiento ventana de una aplicación. - 153 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 2.6. Estructura de un programa Windows GUI. Hay algunas diferencias entre la estructura de un programa C/C++ normal y la correspondiente a un programa Windows GUI. Algunas de estas diferencias se deben a que los programas GUI están basados en mensajes mientras que otras son sencillamente debidas a que siempre hay un determinado número de tareas que hay que realizar. // Ficheros include #include <windows.h> // Prototipos LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM); // Función de entrada int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) { // Declaración // Inicialización // Bucle de mensajes return Message.wParam; } // Definición de funciones 2.6.1. Cabeceras. Lo primero que hay que hacer para poder usar las funciones del API de Windows es incluir al menos un fichero de cabecera, pero generalmente no bastará con uno. La librería windows.h contiene la mayoría de los ficheros de cabecera corrientes en aplicaciones GUI, pero se pueden incluir sólo los que se necesiten, siempre que se sepa cuáles son. Por ejemplo, la función WinMain está declarada en el fichero de cabecera winbase.h. - 154 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Generalmente esto resultará incómodo, ya que para cada nueva función, mensaje o estructura habrá que comprobar, y si es necesario, incluir nuevos ficheros. Por ello se usa directamente windows.h. 2.6.2. Prototipos. Cada tipo (o clase) de ventana que se use en un programa (normalmente sólo será una), o cuadro de diálogo (puede haber muchos), necesitará un procedimiento propio, que se debe declarar y definir. Siguiendo la estructura de un programa C, esta es la zona normal de declaración de prototipos. 2.6.3. Función de de entrada WinMain. La función de entrada de un programa Windows es “WinMain”, en lugar de la conocida “main”. Normalmente, la definición de esta función cambia muy poco de unas aplicaciones a otras. Se divide en tres partes claramente diferenciadas: declaración, inicialización y bucle de mensajes. 2.6.3.1. Parámetros de entrada de WinMain. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) La función WinMain tiene cuatro parámetros de entrada: o hInstance: es un manipulador para la instancia del programa que se esté ejecutando. Cada vez que se ejecuta una aplicación, Windows crea una instancia para ella, y le pasa un manipulador de dicha instancia a la aplicación. o hPrevInstance: es un manipulador a instancias previas de la misma aplicación. Como Windows es multitarea, pueden existir varias versiones - 155 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. de la misma aplicación ejecutándose, varias instancias. En Windows 3.1, este parámetro servía para saber si la aplicación ya se estaba ejecutando, y de ese modo se podían compartir los datos comunes a todas las instancias. Pero eso era antes, ya que Win32 usa un segmento distinto para cada instancia y este parámetro es siempre NULL, sólo se conserva por motivos de compatibilidad. o lpszCmdParam: esta cadena contiene los argumentos de entrada del comando de línea. o nCmdShow: este parámetro especifica cómo se mostrará la ventana. Se recomienda no usar este parámetro en la función ShowWindow la primera vez que ésta es llamada. En su lugar debe usarse el valor SW_SHOWDEFAULT. 2.6.3.2. Función WinMain típica. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) { HWND hwnd; /* Manipulador de ventana */ MSG mensaje; /* Mensajes recibidos por la aplicación */ WNDCLASSEX wincl; /*Estructura de datos para la clase de ventana*/ /* Inicialización: */ /* Estructura de la ventana */ wincl.hInstance = hInstance; wincl.lpszClassName = "NOMBRE_CLASE"; wincl.lpfnWndProc = WindowProcedure; wincl.style = CS_DBLCLKS; wincl.cbSize = sizeof(WNDCLASSEX); /* Usar icono y puntero por defecto */ - 156 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor(NULL, IDC_ARROW); wincl.lpszMenuName = NULL; wincl.cbClsExtra = 0; wincl.cbWndExtra = 0; wincl.hbrBackground = (HBRUSH)COLOR_BACKGROUND; /* Registrar la clase de ventana, si falla, salir del programa */ if(!RegisterClassEx(&wincl)) return 0; hwnd = CreateWindowEx( 0, "NOMBRE_CLASE", "Ventana 1", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, HWND_DESKTOP, NULL, hInstance, NULL ); ShowWindow(hwnd, SW_SHOWDEFAULT); /* Bucle de mensajes: */ while(TRUE == GetMessage(&mensaje, 0, 0, 0)) { TranslateMessage(&mensaje); DispatchMessage(&mensaje); } return mensaje.wParam; } - 157 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 2.6.3.3. Declaración. En la primera zona se declaran las variables que se necesitan para la función WinMain, que como mínimo serán tres: o HWND hwnd: es un manipulador para la ventana principal de la aplicación. Se sabe pues que la aplicación necesitará al menos una ventana. o MSG mensaje: es una variable para manipular los mensajes que lleguen a la aplicación. o WNDCLASSEX wincl: es una estructura que se usará para registrar la clase particular de ventana que se usará en la aplicación. 2.6.3.4. Inicialización. Esta zona se encarga de registrar la clase o clases de ventana, crear la ventana y visualizarla en pantalla. Para registrar la clase primero hay que rellenar adecuadamente la estructura WNDCLASSEX, que define algunas características que serán comunes a todas las ventanas de una misma clase como color de fondo, icono, menú por defecto, el procedimiento de ventana, etc. Después hay que llamar a la función RegisterClassEx. A continuación se crea la ventana usando la función CreateWindowEx. Cualquiera de estas dos funciones devuelve un manipulador de ventana que se puede necesitar en otras funciones como, por ejemplo, la función ShowWindow. Lo descrito anteriormente es fundamental pero esto no muestra la ventana en la pantalla. Para que la ventana sea visible hay que llamar a la función ShowWindow. La primera vez que se llama a esta función, después de - 158 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. crear la ventana, se puede usar el parámetro nCmdShow de WinMain como parámetro o usar el valor SW_SHOWDEFAULT, opción ésta recomendada por Windows. 2.6.3.5. Bucle de mensajes. Este es el núcleo de la aplicación. Tal y como se observa en el código, el programa permanece en este bucle mientras la función GetMessage devuelve un valor TRUE. while(TRUE == GetMessage(&mensaje, 0, 0, 0)) { TranslateMessage(&mensaje); DispatchMessage(&mensaje); } La función TranslateMessage se usa para traducir los mensajes de teclas virtuales a mensajes de carácter. Los mensajes traducidos se reenvían a la lista de mensajes del proceso, y se recuperarán con las siguientes llamadas a GetMessage. La función DispatchMessage envía el mensaje al procedimiento de ventana, donde será tratado adecuadamente. El procedimiento de ventana se explicará en el punto 2.7 y una vez explicado se estará en disposición de crear una interfaz gráfica de usuario mediante MinGW Developer Studio. 2.6.4. Definición de funciones. En esta zona se definen, entre otras cosas, los procedimientos de ventana, que se encargan de procesar los mensajes que lleguen a cada ventana. Los procedimientos de ventana se explicarán a continuación. - 159 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 2.7. El procedimiento de ventana. Cada ventana tiene una función asociada que se conoce como procedimiento de ventana, y es la encargada de procesar adecuadamente todos los mensajes enviados a una determinada clase de ventana. Es la responsable de todo lo relativo al aspecto y al comportamiento de una ventana. Normalmente, estas funciones están basadas en una estructura "switch" donde cada "case" corresponde a un determinado tipo de mensaje. 2.7.1. Sintaxis. LRESULT CALLBACK WindowProcedure ( HWND hwnd, // Manipulador de ventana UINT mensaje, // Mensaje WPARAM wParam, // Parámetro palabra, varía LPARAM lParam // Parámetro doble palabra, varía ); o hwnd es el manipulador de la ventana a la que está destinado el mensaje. o mensaje es el código del mensaje. o wParam es el parámetro de tipo palabra asociado al mensaje. o lParam es el parámetro de tipo doble palabra asociado al mensaje. Se puede considerar este prototipo como una plantilla para crear procedimientos de ventana. El nombre de la función puede cambiar, pero el valor de retorno y los parámetros deben ser los mismos. El miembro lpfnWndProc de la estructura WNDCLASSEX es un puntero a una función de este tipo. Esa función es la que se encargará de procesar todos los mensajes para esa clase de ventana. Cuando se registra la clase de ventana, se tiene que asignar a ese miembro el puntero al procedimiento de ventana. - 160 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 2.7.2. Prototipo de procedimiento de ventana. LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM); 2.7.3. Implementación de procedimiento de ventana simple. /* Esta función es llamada por la función del API DispatchMessage() */ LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT mensaje, WPARAM wParam, LPARAM lParam) { switch (mensaje) /* manipulador del mensaje */ { case WM_DESTROY: /* envía un mensaje WM_QUIT a la cola de mensajes */ PostQuitMessage(0); break; default: /* para los mensajes de los que no se ocupa el usuario */ return DefWindowProc(hwnd, mensaje, wParam, lParam); } return 0; } En general, habrá tantos procedimientos de ventana como programas diferentes y todos serán distintos, pero también tendrán algo en común: todos ellos procesarán los mensajes que lleguen a una clase de ventana. En este ejemplo sólo se procesa un tipo de mensaje, se trata de WM_DESTROY que es el mensaje que se envía a una ventana cuando se recibe un comando de cerrar, ya sea por menú o mediante el icono de aspa en la esquina superior derecha de la ventana. Este mensaje sólo sirve para informar a la aplicación de que el usuario tiene la intención de abandonar la aplicación, y le da una oportunidad de dejar las cosas en su sitio: cerrar ficheros, liberar memoria, guardar variables, etc. Esto lo hace enviándole un mensaje WM_QUIT, mediante la función PostQuitMessage. - 161 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. El resto de los mensajes se procesan en el caso "default", y simplemente se cede su tratamiento a la función del API que hace el proceso por defecto para cada mensaje, DefWindowProc. Este es el camino que sigue el mensaje WM_QUIT cuando llega, ya que el proceso por defecto para este mensaje es cerrar la aplicación. 2.8. Ejemplo GUI mediante MinGW Developer Studio. Una vez explicados los procedimientos de ventana ya se puede mostrar el primer ejemplo de interfaz gráfica de usuario mediante MinGW Developer Studio. El siguiente segmento de código muestra una ventana por pantalla. #include <windows.h> /* Declaración del procedimiento de ventana */ LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) { HWND hwnd; /* Manipulador de ventana */ MSG mensaje; /* Mensajes recibidos por la aplicación */ WNDCLASSEX wincl; /*Estructura de datos para la clase de ventana*/ /* Inicialización: */ /* Estructura de la ventana */ wincl.hInstance = hInstance; wincl.lpszClassName = "NOMBRE_CLASE"; wincl.lpfnWndProc = WindowProcedure; wincl.style = CS_DBLCLKS; wincl.cbSize = sizeof(WNDCLASSEX); /* Usar icono y puntero por defecto */ wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION); - 162 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. wincl.hCursor = LoadCursor(NULL, IDC_ARROW); wincl.lpszMenuName = NULL; wincl.cbClsExtra = 0; wincl.cbWndExtra = 0; wincl.hbrBackground = (HBRUSH)COLOR_BACKGROUND; /* Registrar la clase de ventana, si falla, salir del programa */ if(!RegisterClassEx(&wincl)) return 0; hwnd = CreateWindowEx( 0, "NOMBRE_CLASE", "Ventana 1", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, HWND_DESKTOP, NULL, hInstance, NULL ); ShowWindow(hwnd, SW_SHOWDEFAULT); /* Bucle de mensajes: */ while(TRUE == GetMessage(&mensaje, 0, 0, 0)) { TranslateMessage(&mensaje); DispatchMessage(&mensaje); } return mensaje.wParam; } /* Esta función es invocada por la función DispatchMessage() LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT */ mensaje, WPARAM wParam, LPARAM lParam) { switch (mensaje) /* manipulador de mensaje */ { case WM_DESTROY: PostQuitMessage (0); /* Envía el mensaje WM_QUIT a la cola de mensajes */ - 163 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. break; default: /* Mensajes que no se quieren manejar */ return DefWindowProc (hwnd, mensaje, wParam, lParam); } return 0; } La salida por pantalla tras ejecutar el código anterior sería la siguiente: - 164 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 3 Menús y cuadros de diálogo - 165 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 3. Menús y cuadros de diálogo. En el presente capítulo se explican dos herramientas fundamentales a la hora de desarrollar interfaces gráficas de usuario (GUI). Estas herramientas son los menús y los cuadros de diálogo. 3.1. Menús. Una vez explicado el esqueleto de una aplicación gráfica, se verá una herramienta fundamental de comunicación con ella: el menú. Un menú es una ventana un tanto especial, del tipo pop-up, que contiene una lista de comandos u opciones entre las cuales el usuario puede elegir. Cuando los menús se usan en una aplicación, normalmente se agrupan bajo una barra horizontal, que es también un menú, dividida en varias zonas o ítems. Cada ítem de un menú, salvo los separadores y aquellos que despliegan nuevos menús, tiene asociado un identificador. El valor de ese identificador se usará por parte de la aplicación para saber qué opción activó el usuario y decidir las acciones a tomar en consecuencia. La forma más sencilla y frecuente de implementar menús es mediante ficheros de recursos (extensión *.rc). A la hora de trabajar con ficheros de recursos es importante adquirir algunas buenas costumbres como son: o Usar siempre etiquetas como identificadores de los ítems de los menús, y nunca valores numéricos literales. o Crear un fichero de cabecera con las definiciones de los identificadores. Se llamará, por ejemplo, “ids.h” - 166 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o Este fichero de cabecera se incluirá tanto en el fichero de recursos como en el del código fuente de la aplicación. A la hora de elaborar el fichero de recursos existen dos opciones: mediante el editor de recursos del compilador o mediante un editor de texto (por ejemplo, el Bloc de notas). La primera alternativa se explicará en el siguiente capítulo mientras que la primera se explicará a continuación. La creación de ficheros de recursos mediante un editor de texto ayudará a entender el funcionamiento y utilidad de estos ficheros antes de explicar su creación por medio del editor de recursos del compilador. Dicho esto se procede a explicarla. Supóngase que se quiere crear una aplicación con un menú que contenga dos ítems: “Abrir” y “Salir”. Como ya se ha comentado anteriormente, estos ítems tendrán asociado un identificador que debe ser declarado en el fichero de cabecera “ids.h”. Es por ello que la primera línea del fichero de recursos debe ser: #include “ids.h” Siendo el fichero de cabecera “ids.h” el siguiente: #define ABRIR 1000 #define SALIR 1001 Una vez se ha hecho el include del fichero “ids.h” se procede a elaborar el fichero de recursos. Dicho fichero debe contener la declaración del menú así como de los ítems que lo componen, que en este caso serán dos. El primer ítem (ABRIR) tendrá el identificador “1000” mientras que el segundo (SALIR) tendrá el “1001”. Una vez dicho esto se muestra el fichero de recursos ya creado: - 167 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Menu MENU BEGIN POPUP "&Menú" BEGIN MENUITEM "&Abrir", ABRIR MENUITEM SEPARATOR MENUITEM "&Salir", SALIR END END El fichero de recursos sobre estas líneas permite crear la estructura del menú de forma fácil. El ejemplo crea una barra de menú con una columna “Menú”, con dos opciones: “Abrir” y “Salir”, y con un separador entre ambas. La sintaxis es sencilla, se define el menú mediante una cadena identificadora, sin comillas, seguida de la palabra MENU. Entre las palabras BEGIN y END se pueden incluir ítems, separadores u otras columnas. Para incluir columnas se usa una sentencia del tipo POPUP seguida de la cadena que se mostrará como texto en el menú. Cada POPUP se comporta del mismo modo que un MENU. Los ítems se crean usando la palabra MENUITEM seguida de la cadena que se mostrará en el menú, una coma, y el comando asignado a ese ítem, que será una macro definida en el fichero “ids.h”. Los separadores se crean usando MENUITEM seguido de la palabra SEPARATOR. Como se puede observar en el ejemplo, las cadenas que se muestran en el menú contienen el símbolo & en su interior, por ejemplo “&Abrir”. Este símbolo indica que la siguiente letra puede usarse para activar la opción del menú desde el teclado, usando la tecla [ALT] más la letra que sigue al símbolo &. Para indicar dicha situación, en pantalla se muestra esa letra subrayada, por ejemplo “Abrir”. - 168 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. El último paso que se debe realizar es usar el menú creado desde el fichero fuente. Para ello se deben realizar los siguientes pasos: o Incluir el fichero de cabecera “ids.h” mediante la sentencia #include “ids.h”. o Asignar el menú creado como menú por defecto de la clase. Para ello se realiza la siguiente asignación en la función WinMain: WNDCLASSEX wincl; ... wincl.lpszMenuName = “Menu”; Otra alternativa, más compleja que la explicada, a la hora de usar un menú es la de cargarlo y asignarlo a la ventana por medio de la función LoadMenu en la llamada a CreateWindowEx. El código necesario para llevar a cabo esta alternativa se muestra a continuación: hwnd = CreateWindowEx( 0, "NOMBRE_CLASE", "Ventana 1", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, HWND_DESKTOP, LoadMenu(hInstance, "Menu"), /* Carga y asignación de menú */ NULL, hInstance, NULL ); A continuación se explicará la función MessageBox que se empleará para mostrar cuadros de mensaje una vez pulsada una opción del menú. - 169 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 3.1.1. Función MessageBox. Una vez explicada la forma de crear un menú y asignarlo a una ventana se explicará un mecanismo muy simple para informar al usuario de cualquier situación que se produzca en la aplicación. Este mecanismo es el cuadro de mensaje (message box), que consiste en una pequeña ventana con un mensaje para el usuario y uno o varios botones, según el tipo de cuadro de mensaje que se use. Para visualizar un cuadro de mensaje simple se usará la función MessageBox. La función MessageBox es una función perteneciente a la cabecera winuser.h que crea, muestra y ejecuta un cuadro de mensaje. El cuadro de mensaje contiene un mensaje definido por la aplicación y un título, así como cualquier combinación de iconos predefinidos y botones. La sintaxis de la función es la siguiente: int MessageBox( HWND hwnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType ); // // // // manipulador de la ventana propietaria dirección del texto del mensaje dirección del texto del título estilo del cuadro de mensaje Los parámetros de la función tienen el siguiente significado: o hWnd: identifica a la ventana propietaria del cuadro de mensaje a crear. Si este parámetro es NULL, el cuadro de mensaje no tendrá ventana propietaria. o lpText: apunta a una cadena terminada en cero que contiene el mensaje a mostrar. - 170 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o lpCaption: apunta a una cadena terminada en cero usada como título para el cuadro de diálogo. Si este parámetro es NULL, se usará el título por defecto de Error. o uType: especifica el contenido y comportamiento del cuadro de diálogo. A continuación se muestra una tabla con algunos de los valores más empleados del parámetro uType: Valor MB_ABORTRETRYIGNORE MB_ICONEXCLAMATION MB_ICONQUESTION MB_ICONSTOP MB_OK MB_OKCANCEL MB_RETRYCANCEL MB_YESNO MB_YESNOCANCEL Significado El cuadro de mensaje contiene tres botones: Anular, Reintentar e Omitir. Se mostrará un icono de exclamación. Se mostrará un icono con una interrogación. Se mostrará un icono con un signo de stop. El cuadro de mensaje contiene un único botón de Aceptar. El cuadro de mensaje contiene dos botones: Aceptar y Cancelar. El cuadro de mensaje contiene dos botones: Reintentar y Cancelar. El cuadro de mensaje contiene dos botones: Sí y No. El cuadro de mensaje contiene tres botones: Sí, No y Cancelar. - 171 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. A continuación se mostrará un ejemplo de un pequeño cuadro de mensaje: MessageBox(hwnd, “Fichero guardado OK.”, “Guardar Fichero”, MB_OK); La salida por pantalla sería la siguiente: Una vez explicada la manera de crear cuadros de mensaje proseguimos con el ejemplo del menú. A pesar de que el menú ya había sido creado y asociado a la ventana, sus dos opciones (Abrir y Salir) carecían de comportamiento. Es por ello que ahora se está en disposición de asignar a cada opción un cuadro de mensaje que informe acerca del comando del menú que se ha pulsado. Al pulsar una opción del menú se produce una activación del mismo. Esta activación se recibe mediante un mensaje WM_COMMAND. Para procesar estos mensajes se utilizará la palabra de menor peso del parámetro wParam del mensaje. Es por ello que dentro del case WM_COMMAND en el procedimiento de ventana se hará un switch en función del identificador del ítem del parámetro wParam. Para extraer dicho identificador se emplea la macro LOWORD. Una vez hecho esto ya sólo falta mostrar en cada case correspondiente a cada ítem del menú un cuadro de mensaje que informe acerca de la opción pulsada. A continuación se muestra el código del procedimiento de ventana para procesar los mensajes del menú: - 172 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT mensaje, WPARAM wParam, LPARAM lParam) { switch (mensaje) /* manipulador del mensaje */ { case WM_COMMAND: switch(LOWORD(wParam)) { case ABRIR: MessageBox(hwnd, "Se ha pulsado la opción Abrir.", "Se ha pulsado la opción Salir.", "Mensaje de menú", MB_OK); break; case SALIR: MessageBox(hwnd, "Mensaje de menú", MB_OK); PostQuitMessage(0); /* envía un mensaje WM_QUIT a la cola de mensajes */ break; } break; case WM_DESTROY: PostQuitMessage(0); /* envía un mensaje WM_QUIT a la cola de mensajes */ break; default: /* Mensajes que no se quieren manejar */ return DefWindowProc(hwnd, mensaje, wParam, lParam); } return 0; } También se puede ver en el código sobre estas líneas que cuando se pulsa la opción “Salir” se sale de la aplicación mediante la función PostQuitMessage. Con este último trozo de código se da por terminada la explicación del ejemplo de aplicación de menú con cuadros de mensaje. En el siguiente apartado se muestra el código de todos los ficheros del ejemplo así como las salidas por pantalla. - 173 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 3.1.2. Ejemplo completo de menús y cuadros de mensaje. En este apartado se muestra el contenido de los ficheros necesarios para desarrollar el ejemplo de menús y cuadros de mensaje explicado anteriormente así como las salidas por pantalla de la aplicación final. Se mostrarán, pues, los ficheros “ids.h”, “menu.rc” y “menu.c”. Fichero de identificadores (fichero ids.h) #define ABRIR 1000 #define SALIR 1001 Fichero de recursos (fichero menu.rc) #include "ids.h" Menu MENU BEGIN POPUP "&Menú" BEGIN MENUITEM "&Abrir", ABRIR MENUITEM SEPARATOR MENUITEM "&Salir", SALIR END END - 174 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Programa Principal (fichero menu.c) #include <windows.h> #include "ids.h" /* Declaración del procedimiento de ventana */ LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) { HWND hwnd; /* Manipulador de ventana */ MSG mensaje; /* Mensajes recibidos por la aplicación */ WNDCLASSEX wincl; /* Estructura de datos para la clase de ventana */ /* Estructura de la ventana */ wincl.hInstance = hInstance; wincl.lpszClassName = "NOMBRE_CLASE"; wincl.lpfnWndProc = WindowProcedure; wincl.style = CS_DBLCLKS; wincl.cbSize = sizeof (WNDCLASSEX); /* Usar icono y puntero por defector */ wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor (NULL, IDC_ARROW); wincl.lpszMenuName = "Menu"; /* Con menú “Menu” */ wincl.cbClsExtra = 0; wincl.cbWndExtra = 0; wincl.hbrBackground = (HBRUSH)COLOR_BACKGROUND; /* Registrar la clase de ventana, si falla, salir del programa */ if(!RegisterClassEx(&wincl)) return 0; hwnd = CreateWindowEx( 0, "NOMBRE_CLASE", "Ventana 1", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, HWND_DESKTOP, //LoadMenu(hInstance, "Menu"), /* Otra alternativa */ NULL, hInstance, NULL ); ShowWindow(hwnd, SW_SHOWDEFAULT); - 175 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. /* Bucle de mensajes */ while(TRUE == GetMessage(&mensaje, 0, 0, 0)) { TranslateMessage(&mensaje); DispatchMessage(&mensaje); } return mensaje.wParam; } /* Esta función es invocada por la función DispatchMessage() */ LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT mensaje, WPARAM wParam, LPARAM lParam) { switch (mensaje) /* manipulador del mensaje */ { case WM_COMMAND: switch(LOWORD(wParam)) { case ABRIR: MessageBox(hwnd, "Se ha pulsado la opción Abrir.", "Mensaje de menú", MB_OK); break; case SALIR: MessageBox(hwnd, "Se ha pulsado la opción Salir.", "Mensaje de menú", MB_OK); PostQuitMessage(0); /* envía un mensaje WM_QUIT a la cola de mensajes */ break; } break; case WM_DESTROY: PostQuitMessage(0); /* envía un mensaje WM_QUIT a la cola de mensajes */ break; default: /* Mensajes que no se quieren manejar */ return DefWindowProc(hwnd, mensaje, wParam, lParam); } return 0; } - 176 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. A continuación se muestra la salida por pantalla tras la ejecución del código mostrado así como el comportamiento de la aplicación al pulsar cada una de las dos opciones del menú. Al pulsar la opción “Abrir” del menú aparece el siguiente cuadro de mensaje: Y al pulsar la opción “Salir” aparece el siguiente cuadro de mensaje tras el cual se cerrará la aplicación: - 177 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 3.2. Cuadros de diálogo. Los cuadros de diálogo son la forma de ventana más habitual de comunicación entre una aplicación gráfica y el usuario. Para facilitar la tarea del usuario a la hora de introducir datos existen varios tipos de controles, cada uno de ellos diseñado para un tipo específico de información. Los más comunes son los “static”, “edit”, “button”, “listbox”, “scroll”, “combobox”, “group”, “checkbutton” y “radiobutton”. Un cuadro de diálogo es una ventana normal aunque con algunas peculiaridades. También tiene su procedimiento de ventana (que recibirá el nombre de procedimiento de diálogo), pero puede devolver un valor a la ventana que lo invoque. La forma más sencilla y frecuente de implementar cuadros de diálogo es mediante ficheros de recursos (extensión *.rc). Al igual que en el apartado anterior, se explicará la creación de dicho fichero mediante un editor de texto ya que ayudará a entender el funcionamiento y la estructura del fichero antes de explicar su creación por medio del editor de recursos del compilador en el próximo capítulo. A continuación se muestra el código del fichero de recursos necesario para crear un menú con un ítem llamado “Diálogo” y un cuadro de diálogo con un texto (“Mensaje de prueba”) y un botón de “Aceptar”: #include <windows.h> #include "ids.h" Menu MENU BEGIN POPUP "&Menú" BEGIN MENUITEM "&Diálogo", DIALOGO END - 178 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. END DialogoPrueba DIALOG 0, 0, 118, 48 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION CAPTION "Diálogo de prueba" FONT 8, "Helv" BEGIN CONTROL "Mensaje de prueba", TEXTO, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 9, 84, 8 CONTROL "Aceptar", IDOK, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 56, 26, 50, 14 END Se necesita incluir el fichero “windows.h” ya que en él se definen muchas constantes, como por ejemplo “IDOK” que es el identificador que se usa para el botón de “Aceptar”. También se necesita el fichero “ids.h” para definir los identificadores que se usarán en el programa, por ejemplo, el identificador de la opción del menú para abrir el diálogo. A continuación se muestra el fichero “ids.h”: #define TEXTO 1000 #define DIALOGO 1001 Lo primero que se definirá es un menú para poder comunicarle a la aplicación que se quiere abrir un cuadro de diálogo. A continuación está la definición del diálogo. La primera línea define un diálogo llamado “DialogoPrueba” mediante la palabra DIALOG, así como las coordenadas y dimensiones del diálogo. En cuanto a los estilos, las constantes para definir los estilos de ventana comienzan con “WS_” mientras que los estilos de diálogos comienzan con - 179 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. “DS_”. Los estilos que se han definido en el fichero de recursos mediante la palabra STYLE son los siguientes: o DS_MODALFRAME: indica que se creará un cuadro de diálogo con un marco de dialogbox modal que puede combinarse con una barra de título y un menú de sistema. o WS_POPUP: crea una ventana “pop-up”. o WS_VISIBLE: crea una ventana inicialmente visible. o WS_CAPTION: crea una ventana con una barra de título. La siguiente línea del fichero es la de CAPTION y en ella se especifica el texto que aparecerá en la barra de título del diálogo. La línea de FONT sirve para especificar el tamaño y el tipo de fuente de caracteres que usará el diálogo. Después se encuentra la zona de controles en la que se define un texto estático y un botón. Un control estático (static) sirve para mostrar textos o rectángulos, que se pueden usar para informar al usuario de algo, como etiquetas o simplemente como adorno. El control button sirve para que el usuario se comunique con el diálogo. A continuación se explica en detalle la definición del control button. CONTROL "Aceptar", IDOK, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 56, 26, 50, 14 o CONTROL es una palabra clave que indica que se va a definir un control. o A continuación, en el parámetro text se introduce el texto que se mostrará en su interior. o id es el identificador del control. La aplicación recibirá este identificador junto con el mensaje WM_COMMAND cuando el usuario active el botón. La etiqueta IDOK está definida en el fichero windows.h. - 180 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o class es la clase de control, en este caso “button”. o style es el estilo de control que se quiere. En este caso es una combinación de varios estilos de button y varios de ventana: o BS_PUSHBUTTON: crea un botón corriente que envía un mensaje WM_COMMAND a su ventana padre cuando el usuario selecciona el botón. o BS_CENTER: centra el texto horizontalmente en el área del botón. o WS_CHILD: crea el control como una ventana hija. o WS_VISIBLE: crea una ventana inicialmente visible. o WS_TABSTOP: define un control que puede recibir el foco del teclado cuando el usuario pulsa la tecla TAB. Presionando la tecla TAB, el usuario mueve el foco del teclado al siguiente control con el estilo WS_TABSTOP. o Coordenada x del control. o Coordenada y del control. o Width: anchura del control. o Height: altura del control. 3.2.1. Procedimiento de diálogo. Como ya se ha comentado anteriormente, un diálogo es básicamente una ventana, y al igual que ésta, necesita un procedimiento asociado que procese los mensajes que le sean enviados, en este caso, un procedimiento de diálogo. La sintaxis es la siguiente: BOOL CALLBACK DialogProc( HWND hwndDlg, // Manipulador del cuadro de diálogo UINT mensaje, // Mensaje WPARAM wParam, // Primer parámetro del mensaje LPARAM lParam ); // Segundo parámetro del mensaje o hwndDlg identifica el cuadro de diálogo y es el manipulador de la ventana a la que está destinado el mensaje. - 181 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. o mensaje es el código del mensaje. o wParam es el parámetro de tipo palabra asociado al mensaje. o lParam es el parámetro de tipo doble palabra asociado al mensaje. La diferencia fundamental con el procedimiento de ventana es el tipo de valor de retorno, que en el caso del procedimiento de diálogo es de tipo booleano. Excepto en la respuesta al mensaje WM_INITDIALOG, el procedimiento de diálogo debe devolver un valor no nulo si procesa el mensaje y cero si no lo hace. Cuando responde a un mensaje WM_INITDIALOG, el procedimiento de diálogo debe devolver cero si llama a la función SetFocus para poner el foco a uno de los controles del cuadro de diálogo. En otro caso debe devolver un valor distinto de cero, y el sistema pondrá el foco en el primer control del diálogo que pueda recibirlo. El prototipo del procedimiento de diálogo es el siguiente: BOOL CALLBACK DialogProc(HWND,UINT, WPARAM, LPARAM); A la hora de implementar el procedimiento de diálogo para el ejemplo explicado se debe analizar el diálogo creado. Éste sólo puede proporcionar un comando, así que sólo se deberá responder a un tipo de mensaje WM_COMMAND y al mensaje WM_INITDIALOG. Tal y como se ha comentado, el mensaje WM_INITDIALOG debe devolver un valor distinto de cero si no se llama a SetFocus, como es el caso. Este mensaje se usará para inicializar el diálogo antes de que sea visible para el usuario, siempre que haya algo que inicializar, claro. - 182 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Cuando se procese el mensaje WM_COMMAND, que será siempre el que procede del único botón del diálogo, se cerrará el diálogo llamando a la función EndDialog y se devolverá un valor distinto de cero. En cualquier otro caso de devolverá el valor FALSE, ya que no se estará procesando el mensaje. El procedimiento de diálogo será el siguiente: BOOL CALLBACK DlgProc(HWND hDlg, UINT mensaje, WPARAM wParam, LPARAM lParam) { switch (mensaje) /* manipulador del mensaje */ { case WM_INITDIALOG: return TRUE; case WM_COMMAND: EndDialog(hDlg, FALSE); return TRUE; } return FALSE; } Una vez implementado el procedimiento de diálogo ya sólo falta crear el cuadro de diálogo. Para ello se usará un comando (opción) de menú, por lo que el diálogo se activará desde el procedimiento de ventana. El código necesario para crear el cuadro de diálogo en el procedimiento de ventana es el siguiente: - 183 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT mensaje, WPARAM wParam, LPARAM lParam) { static HINSTANCE hInstance; switch (mensaje) /* manipulador del mensaje */ { case WM_CREATE: hInstance = ((LPCREATESTRUCT)lParam)->hInstance; return 0; break; case WM_COMMAND: switch(LOWORD(wParam)) { case DIALOGO: DialogBox(hInstance, "DialogoPrueba", hwnd, DlgProc); break; } break; case WM_DESTROY: PostQuitMessage(0); /* envía un mensaje WM_QUIT a la cola de mensajes */ break; default: /* Mensajes que no se quieren manejar */ return DefWindowProc(hwnd, mensaje, wParam, lParam); } return 0; } En este procedimiento hay una serie de novedades que se explicarán a continuación. En primer lugar, se ha declarado una variable estática “hInstance” para tener siempre disponible un manipulador de la instancia actual. Para inicializar este valor se hace uso del mensaje WM_CREATE, que se envía a una ventana cuando es creada, antes de que se visualice por primera vez. Se aprovecha el hecho de que el procedimiento de ventana sólo recibe una - 184 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. vez este mensaje y de que lo hace antes de poder recibir ningún otro mensaje o comando. El mensaje WM_CREATE tiene como parámetro en lParam un puntero a una estructura CREATESTRUCT que contiene información sobre la ventana. Para el ejemplo sólo interesará el campo hInstance. Otra novedad es la llamada a la función DialogBox, que es la que crea el cuadro de diálogo. Esta función necesita varios parámetros: o Un manipulador a la instancia de la aplicación, que se ha obtenido al procesar el mensaje WM_CREATE. o Un identificador de recurso de diálogo. Este es el nombre que se utilizó para nombrar al diálogo (entre comillas) cuando se creó el recurso en el fichero de recursos. o Un manipulador a la ventana a la que pertenece el diálogo. o La dirección del procedimiento de ventana que hará el tratamiento del diálogo. 3.2.2. Paso de parámetros a un cuadro de diálogo. A la hora de crear un diálogo existe otra opción además de la ya citada función DialogBox que permite enviar un parámetro extra al procedimiento de diálogo. Esta función recibe el nombre de DialogBoxParam. El parámetro que se envía al procedimiento de ventana es enviado a través del parámetro lParam del procedimiento de diálogo, y puede contener un valor entero o, lo que es mucho más útil, un puntero. Esta función tiene los mismos parámetros que DialogBox, más uno añadido. Este quinto parámetro es el que se usa para recibir valores desde el procedimiento de diálogo. - 185 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Por ejemplo, supóngase que se quiere saber cuántas veces se ha invocado un diálogo. Para ello se llevará la cuenta en el procedimiento de ventana, incrementando esa cuenta cada vez que se reciba un comando u opción del menú para mostrar el diálogo. Además, se pasará ese valor como parámetro lParam al procedimiento de diálogo. A continuación se muestra el procedimiento de ventana con los dos diálogos que se mostrarán en la aplicación: DIALOGO1 (el del apartado anterior) y DIALOGO2 (el que lleva la cuenta del número de veces que se ha invocado). LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT mensaje, WPARAM wParam, LPARAM lParam) { static HINSTANCE hInstance; static int veces; switch (mensaje) /* manipulador del mensaje */ { case WM_CREATE: hInstance = ((LPCREATESTRUCT)lParam)->hInstance; return 0; break; case WM_COMMAND: switch(LOWORD(wParam)) { case DIALOGO1: DialogBox(hInstance, "DialogoPrueba", hwnd, DlgProc); break; case DIALOGO2: veces++; DialogBoxParam(hInstance, DlgProc2, veces); break; } break; case WM_DESTROY: PostQuitMessage(0); break; default: - 186 - "DialogoPrueba", hwnd, Programación Orientada a Objetos en C mediante MinGW Developer Studio. return DefWindowProc(hwnd, mensaje, wParam, lParam); } return 0; } El procedimiento de ventana mostrado tomará el valor de la variable “veces” y lo pasará como parámetro lParam al procedimiento de diálogo. Éste último será el encargado de crear el texto de un control estático mostrando su valor tal y como se muestra a continuación: BOOL CALLBACK DlgProc2(HWND hDlg, UINT mensaje, WPARAM wParam, LPARAM lParam) { char texto[25]; switch (mensaje) /* manipulador del mensaje */ { case WM_INITDIALOG: sprintf(texto, "Veces invocado: %d", lParam); SetWindowText(GetDlgItem(hDlg, TEXTO), texto); return TRUE; case WM_COMMAND: EndDialog(hDlg, FALSE); return TRUE; } return FALSE; } Para conseguir un texto estático a partir del parámetro lParam se ha usado la función estándar sprintf. Posteriormente se usa ese texto para modificar el control estático TEXTO. Por otra parte, la función SetWindowText se usa para cambiar el título de una ventana, pero en este caso sirve para cambiar el texto del control estático. El paso de parámetros a un cuadro de diálogo es de gran utilidad cuando éste se usa para pedir datos al usuario. De este modo se facilita en gran medida - 187 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. el intercambio de datos entre la aplicación y los procedimientos de diálogo y se evita el uso de variables globales. Una vez mostrado el procedimiento de diálogo del cuadro de diálogo DIALOGO2 se da por terminada la explicación del ejemplo de aplicación de menú con cuadros de diálogo. En el siguiente apartado se muestra el código de todos los ficheros del ejemplo así como las salidas por pantalla. - 188 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 3.2.3. Ejemplo completo de cuadros de diálogo. En este apartado se muestra el contenido de los ficheros necesarios para desarrollar el ejemplo de cuadros de diálogo explicado anteriormente así como las salidas por pantalla de la aplicación final. Se mostrarán, pues, los ficheros “ids.h”, “dialogo.rc” y “dialogo.c”. Fichero de identificadores (fichero ids.h) #define TEXTO 1000 #define DIALOGO1 1001 #define DIALOGO2 1002 Fichero de recursos (fichero dialogo.rc) #include <windows.h> #include "ids.h" Menu MENU BEGIN POPUP "&Menú" BEGIN MENUITEM "&Diálogo", DIALOGO1 MENUITEM "&Con parámetro", DIALOGO2 END END DialogoPrueba DIALOG 0, 0, 118, 48 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION CAPTION "Diálogo de prueba" FONT 8, "Helv" BEGIN CONTROL "Mensaje de prueba", TEXTO, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 9, 84, 8 CONTROL "Aceptar", IDOK, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 56, 26, 50, 14 END - 189 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Programa Principal (fichero dialogo.c) #include <windows.h> #include "ids.h" /* Declaración del procedimiento de ventana */ LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK DlgProc2(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) { HWND hwnd; /* Manipulador de ventana */ MSG mensaje; /* Mensajes recibidos por la aplicación */ WNDCLASSEX wincl; /* Estructura de datos para la clase de ventana */ /* Estructura de la ventana */ wincl.hInstance = hInstance; wincl.lpszClassName = "NOMBRE_CLASE"; wincl.lpfnWndProc = WindowProcedure; wincl.style = CS_DBLCLKS; wincl.cbSize = sizeof(WNDCLASSEX); /* Usar icono y puntero por defector */ wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor(NULL, IDC_ARROW); wincl.lpszMenuName = "Menu"; wincl.cbClsExtra = 0; wincl.cbWndExtra = 0; wincl.hbrBackground = (HBRUSH)COLOR_BACKGROUND; /* Registrar la clase de ventana, si falla, salir del programa */ if(!RegisterClassEx(&wincl)) return 0; hwnd = CreateWindowEx( 0, "NOMBRE_CLASE", "Ventana 1", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, HWND_DESKTOP, NULL, hInstance, NULL ); ShowWindow(hwnd, SW_SHOWDEFAULT); /* Bucle de mensajes */ while(TRUE == GetMessage(&mensaje, NULL, 0, 0)) { TranslateMessage(&mensaje); - 190 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. DispatchMessage(&mensaje); } /* Salir con valor de retorno */ return mensaje.wParam; } /* Esta función es invocada por la función DispatchMessage() */ LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT mensaje, WPARAM wParam, LPARAM lParam) { static HINSTANCE hInstance; static int veces; switch (mensaje) /* manipulador del mensaje */ { case WM_CREATE: hInstance = ((LPCREATESTRUCT)lParam)->hInstance; return 0; break; case WM_COMMAND: switch(LOWORD(wParam)) { case DIALOGO1: DialogBox(hInstance, "DialogoPrueba", hwnd, DlgProc); break; case DIALOGO2: veces++; DialogBoxParam(hInstance, "DialogoPrueba", hwnd, DlgProc2, veces); break; } break; case WM_DESTROY: PostQuitMessage(0); /* envía el mensaje WM_QUIT a la cola de mensajes */ break; default: /* Mensajes que no se quieren manejar */ return DefWindowProc(hwnd, mensaje, wParam, lParam); } return 0; } BOOL CALLBACK DlgProc(HWND hDlg, UINT mensaje, WPARAM wParam, LPARAM lParam) { switch (mensaje) /* manipulador del mensaje */ { case WM_INITDIALOG: return TRUE; case WM_COMMAND: EndDialog(hDlg, FALSE); return TRUE; } return FALSE; } - 191 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. BOOL CALLBACK DlgProc2(HWND hDlg, UINT mensaje, WPARAM wParam, LPARAM lParam) { char texto[25]; switch (mensaje) /* manipulador del mensaje */ { case WM_INITDIALOG: sprintf(texto, "Veces invocado: %d", lParam); SetWindowText(GetDlgItem(hDlg, TEXTO), texto); return TRUE; case WM_COMMAND: EndDialog(hDlg, FALSE); return TRUE; } return FALSE; } A continuación se muestra la salida por pantalla tras la ejecución del código mostrado así como el comportamiento de la aplicación al pulsar cada una de las dos opciones del menú. - 192 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Al pulsar la opción “Diálogo” del menú aparece el siguiente cuadro de mensaje: Y al pulsar la opción “Con parámetro” aparece el siguiente cuadro de mensaje que muestra el número de veces que se ha invocado: Si se pulsa más veces mostrará el número total de veces que se ha pulsado: - 193 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 4 Creación de recursos mediante el editor de recursos - 194 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 4. Creación de recursos mediante el editor de recursos. En el presente capítulo se explica la creación de ficheros de recursos (extensión *.rc) mediante el editor de recursos de MinGW Developer Studio. Estos ficheros permiten crear de forma rápida y fácil recursos que se emplean posteriormente en aplicaciones gráficas tal y como se vio en el capítulo anterior con los menús y los cuadros de diálogo. Es precisamente estos dos tipos de recursos en los que se centrará la explicación dado que sus correspondientes ficheros de recursos ya se mostraron en el capítulo anterior. A la hora de crear un fichero de recursos (por medio del editor de recursos del compilador) lo primero que se debe hacer es abrir el editor de recursos de MinGW Developer Studio. Para ello se pulsa la opción Resource Editor del menú Tools o bien se pulsan simultáneamente las teclas Ctrl y R. Una vez que se ha abierto el editor de recursos, lo primero que se debe hacer es crear un proyecto nuevo o, en su defecto, abrir un proyecto ya existente. Para ello se pulsan las opciones New Project o Open Project del menú File. Los iconos de la barra de herramientas asociados a estas dos opciones son y respectivamente. Una vez abierto o creado un proyecto se mostrará en la esquina superior derecha de la aplicación la carpeta del proyecto que contendrá los distintos recursos asociados al proyecto. Si el proyecto es nuevo, se mostrará una carpeta vacía con la palabra Untitled (‘Sin título’) ya que el proyecto aún no tiene nombre. A continuación ya se pueden asociar al proyecto los recursos que se deseen. Para ello, en la opción Project del menú del editor se listan las opciones de recursos que se pueden asociar: desde un menú o un diálogo (opciones Add Menu y Add Dialog) hasta recursos más complejos como un acelerador (opción - 195 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Add Accelerator) o un cuadro de versión (opción Add Versioninfo). Los recursos en los que se centrará la explicación serán los menús y los cuadros de diálogo. A la hora de crear un menú se debe pulsar la citada opción Add Menu situada en la opción Project del editor. Una vez pulsada aparecerá un cuadro en el que se podrán especificar una serie de parámetros como el nombre del menú, el identificador del menú o el identificador de comienzo de los ítems. Además, en este mismo cuadro se deben añadir los ítems que se quieran asociar al menú. Para cada ítem se debe especificar su nombre (Name), el nombre con que aparecerá al ejecutar la aplicación (Caption), así como su identificador. Además, el cuadro muestra otras opciones como si se quiere que aparezca deshabilitado (Disabled), marcado (Checked), si es de tipo String, Bitmap, etc. A continuación se muestra la captura de pantalla del cuadro Menu Editor necesario para crear el menú del ejemplo de menús del capítulo 3. - 196 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Una vez creado el menú y guardado el proyecto se creará un fichero de recursos con extensión *.rc con el siguiente contenido: #define Menu 1000 #define ABRIR 1000 #define SALIR 1001 Menu MENUEX BEGIN MENUITEM "Abrir",ABRIR MENUITEM "",SEPARATOR MENUITEM "Salir",SALIR END A partir de este fichero ya se pueden realizar las modificaciones necesarias para adaptarlo a las necesidades del usuario. La primera de estas modificaciones consistiría en cortar las correspondientes a sentencias include primeras líneas del fichero de identificadores de recursos y pegarlas en el fichero de identificadores ids.h. El identificador correspondiente al menú es opcional por lo que será eliminado. Una vez creado el fichero ids.h con los identificadores de los ítems del menú éste podrá ser añadido al fichero de recursos mediante el comando Include file del menú Project. Una vez pulsado, se mostrará un cuadro llamado Included Files donde aparecerán todos los archivos asociados al fichero de recursos. Para asociar un nuevo fichero se pulsa el botón Add y se selecciona la ubicación del fichero mediante el botón situado a la derecha del nuevo registro de la pestaña Filename. Una vez seleccionado el fichero el cuadro tendrá el siguiente aspecto: - 197 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Finalmente, se pulsa el botón OK y el fichero ids.h ya quedará asociado al proyecto. Este hecho se puede visualizar en la zona de recursos ya que aparecerá el icono Include file tal y como se muestra a continuación: Otra modificación que se debe hacer en el fichero de recursos generado es borrar las comillas de texto vacío asociadas al ítem SEPARATOR. Recuérdese que este ítem se emplea para separar los diferentes ítems pertenecientes a un menú. Por ello, en su declaración no se debe incluir Caption alguna si bien el editor de recursos le asigna por defecto una cadena vacía. Por último, si desea dotar al menú de comportamiento tipo pop-up se tendrá que especificar este hecho manualmente dado que no hay ninguna opción en el editor que permita especificar esta propiedad. Recuérdese que este comportamiento permite agrupar sobre una misma opción del menú varias subopciones. Una vez modificado el fichero para habilitar el comportamiento pop-up y ordenadas las sentencias del mismo tendrá el siguiente aspecto: #include "ids.h" Menu MENUEX BEGIN POPUP "&Menú" BEGIN MENUITEM "Abrir",ABRIR MENUITEM SEPARATOR MENUITEM "Salir",SALIR END END - 198 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Los únicos aspectos diferentes al fichero mostrado en el ejemplo de menús del apartado 3.1.2 serían la palabra clave MENUEX (mismo comportamiento que MENU) y la ausencia del símbolo ‘&’ en los caption de los ítems del menú. Este símbolo indica que la siguiente letra puede usarse para activar la opción del menú desde el teclado, usando la tecla [ALT] más la letra que sigue al símbolo &. Para indicar dicha situación, en pantalla se muestra esa letra subrayada, por ejemplo “Abrir”. Este símbolo puede ser incluido de forma manual a elección del usuario. Una vez finalizada la creación del fichero de recursos utilizado en el ejemplo del apartado 3.2.1 se procede a explicar la creación del fichero empleado en el ejemplo de cuadros de diálogo del apartado 3.2.3. El proceso de creación de la parte del fichero de recursos necesaria para crear el menú desde el que se invocarán los cuadros de diálogo es igual a la explicada anteriormente en este capítulo por lo que se obvia esta explicación. Una vez creada esta parte, el fichero de recursos tendrá el siguiente contenido: #include "ids.h" Menu MENUEX BEGIN POPUP "&Menú" BEGIN MENUITEM "&Diálogo", DIALOGO1 MENUITEM "&Con parámetro", DIALOGO2 END END A continuación se añade al proyecto un cuadro de diálogo. Para ello se pulsa la opción Add Dialog del menú Project. Una vez pulsada, aparecerá en la zona de edición del editor un cuadro de diálogo vacío con el título IDD_DLG asignado por defecto. En la parte derecha del editor aparecerá una lista de propiedades del cuadro de diálogo que se pueden modificar. En principio, el nombre del cuadro de diálogo (Name), el título (Caption) y el identificador (ID) serán los tres parámetros a modificar así como eliminar los botones de maximizar, minimizar y cerrar poniendo a ‘False’ la propiedad SysMenu. Sin - 199 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. embargo, se pueden modificar otros muchos como la fuente del título (Font), el estilo (xStyle) o la altura (Height). La forma de modificar estos parámetros es muy sencilla salvo en el caso del estilo. En este caso, cuando se sitúa el cursor sobre la opción xStyle y se pulsa aparece un botón de flecha desplegable en la parte derecha del cuadro de texto que contiene un número en hexadecimal. Si se pulsa esta flecha desplegable aparece un pequeño cuadro con una secuencia de números en binario tal y como se muestra a continuación: Cada dígito del número binario será un estilo diferente cuyo nombre se mostrará bajo los tres botones de flechas. Si se quiere activar el estilo seleccionado, se pulsa el botón hasta que el correspondiente dígito se encuentre a 1. Para avanzar por los dígitos se emplean las otras dos flechas de dirección. Una vez que los estilos deseados se encuentren a 1 y el resto a cero se pulsa el botón Close. Una vez que los parámetros del cuadro de diálogo se encuentren definidos ya se puede comenzar a añadir al cuadro los controles que se deseen. Los diferentes controles que se pueden añadir se muestran en la zona izquierda del editor de recursos por medio de iconos. En cualquier caso, si se sitúa el cursor sobre un icono aparece el nombre del control asociado por lo que la búsqueda de controles resulta fácil e intuitiva. Los controles que se añadirán al cuadro de diálogo serán: un texto estático (control static) por medio del icono y un botón (control button) por medio del icono . A la hora de añadir el control de tipo static se pulsa sobre el icono correspondiente y se dibuja sobre el cuadro de diálogo el tamaño del control en - 200 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. la posición que se desea colocar. Una vez dibujado el control, aparecerá en el lado derecho de la pantalla una lista de parámetros similar a la que aparecía al añadir el cuadro de diálogo. Los parámetros que se deben modificar son el nombre del control (Name), el texto de la etiqueta (Caption) y el identificador del control (ID). Además, se pueden modificar otros parámetros como la fuente del texto (Font), la alineación del texto (Alignment), el borde del control (Border), la altura (Height) o la anchura (Width). Una vez añadido, el aspecto del cuadro de diálogo es el siguiente: Ahora se procede a añadir el otro control, el botón. Para ello se pulsa el icono correspondiente y se dibuja en el cuadro tal y como se hizo al añadir el control static. Una vez añadido, se deben modificar los parámetros de la lista para cambiar el nombre, el identificador y el texto a mostrar en el botón así como otros parámetros que desee el usuario. Recuérdese que el nombre del botón será IDOK, que es el identificador que se usa para el botón de “Aceptar”. Por ello, se necesita incluir el fichero “windows.h” en el que se define dicha constante. Una vez añadido el botón, el cuadro de diálogo tomará su aspecto final: - 201 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Una vez guardado el proyecto, se generará el fichero con extensión .rc que tendrá el siguiente contenido: #include <windows.h> #include "ids.h" Menu MENUEX BEGIN POPUP "&Menú" BEGIN MENUITEM "&Diálogo",DIALOGO1 MENUITEM "&Con parámetro",DIALOGO2 END END DialogoPrueba DIALOGEX 5,5,146,80 CAPTION "Diálogo de prueba" FONT 8,"Microsoft Sans Serif" STYLE 0x90CF0000 EXSTYLE 0x00000000 BEGIN CONTROL "Mensaje de prueba",TEXTO,"Static", 0x50000001,15,7,116,23,0x00000000 CONTROL "Aceptar",IDOK,"Button",0x50010000,43,43,59,18,0x00000000 END El fichero generado es muy similar al que se obtuvo en el ejemplo del apartado 3.2.3 con las particularidades propias del editor de recursos de MinGW Developer Studio como el estilo en número hexadecimal o el uso de la palabra clave DIALOGEX para crear el diálogo en vez de DIALOG. A pesar de ello, el fichero de recursos generado es perfectamente válido y funciona del mismo modo que el editado manualmente. Sin embargo, es obvio que el ahorro de tiempo empleando el editor de recursos es mucho mayor que editándolo manualmente siempre y cuando se sepa qué parámetros se han de modificar para obtener la apariencia deseada en los recursos cuando se ejecute la aplicación gráfica final. - 202 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. PARTE IV: Valoración y conclusiones - 203 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 1 Valoración económica y planificación - 204 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 1. Valoración económica y planificación. 1.1. Valoración económica. En el presente capítulo se procede a realizar una valoración económica de los costes asociados al desarrollo del proyecto. 1.1.1. Coste de tecnología. Son los costes derivados del equipo hardware necesario para desarrollar el proyecto, así como las licencias necesarias para utilizar las herramientas y los distintos lenguajes de programación empleados en el proyecto. Equipo hardware En el desarrollo del proyecto se precisará, como mínimo, de una estación de trabajo Intel Centrino Duo a 1,83 Ghz, 1 GB RAM y 100 GB de disco duro sobre un sistema operativo Windows XP Professional. Elementos software Los principales elementos software que se necesitarán son los siguientes: o MinGW Developer Studio: la descarga e instalación es gratuita por lo que el único coste asociado al compilador será el tiempo de descarga e instalación que, en cualquier caso, no sobrepasará los 10-15 minutos. o Aplicaciones de ofimática (MS Word, Adobe Acrobat,…): se precisará de una licencia de Microsoft Office 2007 si bien la versión “Hogar y Estudiantes 2007” bastará. Dicha versión tiene un coste aproximado de 130 euros. El resto de aplicaciones de ofimática son - 205 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. de descarga gratuita (Adobe Acrobat) o vienen incluidas en el sistema operativo (Notepad, Paint,…). o Conexión a Internet: se requiere una conexión básica a Internet así como un explorador de Internet como puede ser el propio del sistema operativo (Microsoft Internet Explorer) o bien cualquiera de descarga gratuita (Mozilla Firefox, Safari,…). El coste total de tecnología es el siguiente: DISPOSITIVO COSTE Estación de trabajo 1.000€ Windows XP Professional 250€ Microsoft Office Hogar y Estudiantes 2007 130€ ADSL* 220€ 1.600€ * El precio mensual es de 20€ multiplicado por los 11 meses de desarrollo del proyecto. 1.1.2. Coste de implantación. Estos costes incluyen los costes de desarrollo y personal. Además del Jefe de Proyecto (JP) y el Coordinador y Director de Proyecto, que en este caso son la misma persona, se ha dispuesto de un Programador Junior así como de un Analista Junior para llevar a cabo los ejemplos necesarios para explicar los conceptos teóricos del proyecto. El coste total de implantación se muestra en la siguiente tabla: - 206 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. FUNCIÓN Nº horas Coste / Hora IMPORTE Analista Junior 175 35 6.125€ Programador Junior 145 25 3.625€ Jefe de Proyecto 30 55 1.650€ Coordinador y Director de Proyecto 10 65 650€ 12.050€ Total de costes CONCEPTO Costes de tecnología Costes de implantación COSTE 1.600€ 12.050€ 13.650€ - 207 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. 1.2. Planificación del proyecto. La planificación del proyecto se ha dividido en cinco etapas que comenzaron en octubre del 2007 y han finalizado el 5 de septiembre del 2008 con un paréntesis de una semana en noviembre y abril, y de un mes en febrero y junio debido a los exámenes. Las cinco etapas cubiertas por el proyecto son las siguientes: 1. Estudio del compilador (ECO): Análisis de la herramienta software MinGW Developer Studio. 2. Análisis del compilador en el ámbito de Orientación a Objetos (AOO): Análisis de las posibilidades que ofrece el compilador a la hora de llevar a cabo Programación Orientada a Objetos (POO) mediante el lenguaje de programación C++. 3. Análisis de las librerías gráficas del compilador para desarrollar interfaces gráficas de usuario (GUI) (ALG): Análisis de las opciones que ofrece el compilador a la hora de desarrollar interfaces gráficas de usuario (GUI) empleando el API de Windows (WinAPI). 4. Valoración económica (VE): Estimación de los costes reales del proyecto. 5. Cierre: Finalización del proyecto y entrega del documento al Coordinador y Director. Además, se realizará una actividad paralela a todas las demás, que consistirá en la redacción del documento del proyecto (Memoria). - 208 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Planificación temporal - 209 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 2 Conclusiones - 210 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 2. Conclusiones. Este capítulo pretende poner de manifiesto el papel fundamental que la herramienta MinGW Developer Studio ha desempeñado. Este proyecto ha sido el punto final en la formación académica del autor. Se ha convertido en un gran reto el superar con éxito este proyecto, ya que ha supuesto un esfuerzo personal distribuido en tres fases concretas. La primera fase, el estudio detallado del compilador, se caracterizó por la escasa información de la que se dispuso. Dado que es una herramienta de libre descarga (freeware), la información acerca de ella es prácticamente inexistente. Por ello, requirió un amplio aprendizaje de todas las opciones de las que dispone la herramienta así como de su manejo. Resulta sorprendente la multitud de opciones que ofrece el compilador teniendo en cuenta que es una herramienta de libre difusión. Una vez explorada a fondo, hay que resaltar la flexibilidad de la herramienta de cara al usuario así como lo intuitiva que resulta la navegación por los menús y zonas de la interfaz de la aplicación. Por último, se puso especial empeño en dotar a la documentación elaborada de un elevado nivel de detalle dado que en las correspondientes asignaturas de programación en C que se imparten en primer curso de ingeniería de la escuela se utiliza el compilador y, por tanto, esta documentación de la herramienta podrá ser de ayuda a los estudiantes de las mismas. La segunda fase, la explicación de la programación orientada a objetos (POO) empleando el compilador, exigió repasar conceptos teóricos vistos en la asignatura de programación en JAVA de segundo curso. Además, se tuvo que llevar a cabo un repaso exhaustivo del lenguaje de programación C++ aprendido en la correspondiente asignatura de tercer curso. Una vez finalizado este proceso comenzó la ardua tarea de relacionar conceptos, aplicarlos a la programación usando MinGW Developer Studio y, lo más importante, ampliar dichos conceptos. Resultó fascinante trabajar con conceptos de gran potencia - 211 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. como la herencia o la abstracción y poder aplicarlos de forma práctica empleando el compilador. Por último, decir que la POO en sí no es difícil, sino que lo difícil es programar bien. Si se programa bien, se podrán aprovechar todas las ventajas de la POO y, entre ellas, la más importante: la reusabilidad (reutilización de código). La tercera y última fase, la programación gráfica empleando MinGW Developer Studio, fue sin duda alguna uno de los mayores retos del proyecto. El aprendizaje de la programación usando la API de Windows, nunca antes estudiada, así como el empleo del editor de recursos del compilador supusieron un gran esfuerzo personal y una dedicación intensa. A pesar de ser un tema muy extenso, se explicaron con cierto nivel de detalle los aspectos básicos de la programación gráfica mediante WinAPI empleando MinGW Developer Studio. Por último, resaltar que el empleo del compilador como herramienta de creación de aplicaciones gráficas así como su editor de recursos como herramienta de creación de recursos se caracterizan por una gran sencillez y flexibilidad que permiten al usuario programar interfaces gráficas de usuario de forma rápida e intuitiva a pesar de lo complejo del lenguaje de programación usando la API de Windows. Para finalizar, no se puede cerrar este capítulo de conclusiones sin destacar la grata sorpresa que supuso contemplar que el compilador MinGW Developer Studio sirve para algo más que para crear aplicaciones básicas en lenguaje de programación C. Como resultado de lo aprendido en la asignatura de programación en C de primer curso en la que se empleaba el compilador, existe una opinión generalizada de que el compilador es una herramienta muy sencilla y básica que permite poco más que crear pequeñas aplicaciones en C. Sin embargo, a raíz de lo mostrado en este documento el compilador ofrece una gran variedad de posibilidades que van desde la propia programación en C hasta la programación gráfica empleando la API de Windows pasando por la programación orientada a objetos en C++, la creación de recursos empleando el editor de recursos o la creación de ficheros de cabecera. - 212 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. Capítulo 3 Bibliografía - 213 - Programación Orientada a Objetos en C mediante MinGW Developer Studio. CAPÍTULO 3. Bibliografía. [MRAB00] Programación Elemental en C++. Manual de Referencia Abreviado; Dpto. de Lenguajes y CC. Computación E.T.S.I. Informática Universidad de Málaga; Revisión 1,20. [PLJU07] Pedro López Juárez; Programación III Parte II Tema 2 Introducción al lenguaje C++/CLI; Junio 2007. [UBIC00] Víctor Muñoz; Una breve introducción a C++. [CPAP00] Sergio Luján Mora; C++ paso a paso. [PPHM07] Dr. J.B. Hayet; Programación en C++: polimorfismo; herencia múltiple; Centro de Investigación en Matemáticas; Octubre 2007. [WACC07] Salvador Pozo Coronado; WinAPI con clase: Aplicaciones con API 32; Marzo 2007. [IGUA00] Carlos Marrero Expósito; Interfaz gráfica de usuario: Aproximación semiótica y cognitiva. Direcciones de Internet • www.parinyasoft.com • www.hermetic.ch/cfunlib/debug.htm • www.cppreference.com • www.es.wikipedia.org • www.msdn.microsoft.com/en-us/library/aa383743.aspx • www.winapi.conclase.net - 214 -