C++

Page 1

VE IN RS CL GR IÓN D UYE AT IGITA IS L

C++ es un lenguaje orientado a objetos popular, moderno y en constante evolución. A la hora de desarrollar, es la opción más poderosa y robusta que jamás se haya creado. EN ESTE LIBRO APRENDERÁ: Introducción: programación no estructurada, procedural, modular y orientada a objetos. Análisis y diseño. Fundamentos de C++: diferencias con C, variables, palabras reservadas, constantes, booleanos, operadores, sentencias condicionales y bucles. Aspectos avanzados del lenguaje: entrada y salida, objetos cout y cin, preprocesador, array, funciones, strings y enumeradores. Clases y objetos: diagramas, constructor y destructor, modificadores de acceso, propiedades y métodos estáticos. Gestión de memoria: punteros, operadores new y delete, variables estáticas.

Esta obra es una versión revisada del libro C++, publicado en 2004 por esta misma editorial.

Herencia: métodos inline y constantes, subclases, composición vs. herencia. Polimorfismo: sobrecarga de funciones y de operadores, modificador friend, métodos y destructores virtuales.

array

NIVEL DE USUARIO

-m_iCantElementos : int -m_piArray +FijaTam() +FijaValor() +LeerValor() +Limpiar()

Juego

Básico / Intermedio

Jugador

+RegistrarJugador() +EmpezarPartida()

+RealizarMovida() 1

2

CATEGORÍA Desarrollo

pila -m_iUltimoElementos : int +Insertar() +Extraer() +Vaciar() +FijaTam()

cola -m_iPrimerElementos : int -m_iUltimoElementos : int +Insertar() +Extraer() +Vaciar() +FijaTam()

JugadorBot1

JugadorBot2

+RealizarMovida()

+RealizarMovida()

REDUSERS.com

PROFESOR EN LÍNEA

En nuestro sitio podrá encontrar noticias relacionadas y también participar de la comunidad de tecnología más importante de América Latina.

Ante cualquier consulta técnica relacionada con el libro, puede contactarse con nuestros expertos: profesor@redusers.com.

GRATIS

C++ PROGRAMACIÓN ORIENTADA A OBJETOS

El presente libro tiene el doble objetivo de introducirnos y profundizar tanto en lo que se refiere a la programación orientada a objetos, como al lenguaje C++, que será nuestra principal herramienta a la hora de implementar los conceptos teóricos que vayamos estudiando. A lo largo de los distintos capítulos, conoceremos los fundamentos del lenguaje, su sintaxis básica y la manera de escribir el primer programa en él. Además, veremos aspectos avanzados, como el preprocesador, el uso de arrays, funciones, estructuras, espacios de nombre, clases, objetos y gestión de memoria, entre otros. Analizaremos también herencia, polimorfismo, estructuras de datos dinámicas y plantillas.

VERSIÓN DIGITAL

C++ PROGRAMACIÓN ORIENTADA A OBJETOS

TIPOS DE DATOS Y OPERADORES PREPROCESADOR, ARRAYS, FUNCIONES Y STRINGS DIAGRAMAS DE CLASES Y DE OBJETOS HERENCIA Y POLIMORFISMO ESTRUCTURAS DE DATOS DINÁMICAS Y PLANTILLAS

INCLUYE INTRODUCCIÓN A UML

LENGUAJE UNIFICADO DE MODELADO


TÍTULO:

C++

AUTOR:

Diego Ruiz

COLECCIÓN:

Manuales USERS

FORMATO:

24 x 17 cm

PÁGINAS:

352

Copyright © MMXIV. Es una publicación de Fox Andina en coedición con DÁLAGA S.A. Hecho el depósito que marca la ley 11723. Todos los derechos reservados. Esta publicación no puede ser reproducida ni en todo ni en parte, por ningún medio actual o futuro sin el permiso previo y por escrito de Fox Andina S.A. Su infracción está penada por las leyes 11723 y 25446. La editorial no asume responsabilidad alguna por cualquier consecuencia derivada de la fabricación, funcionamiento y/o utilización de los servicios y productos que se describen y/o analizan. Todas las marcas mencionadas en este libro son propiedad exclusiva de sus respectivos dueños. Impreso en Argentina. Libro de edición argentina. Primera impresión realizada en Sevagraf, Costa Rica 5226, Grand Bourg, Malvinas Argentinas, Pcia. de Buenos Aires en VIII, MMXIV.

ISBN 978-987-1949-64-9

Ruiz, Diego C++ / Diego Ruiz ; coordinado por Gustavo Carballeiro. - 1a ed. - Ciudad Autónoma de Buenos Aires: Fox Andina; Buenos Aires: Dalaga, 2014. 352 p. ; 24 x 17 cm. - (Manual users; 268) ISBN 978-987-1949-64-9 1. Informática. I. Carballeiro, Gustavo, coord. II. Título CDD 005.3


4

PRELIMINARES

El libro de un vistazo En este libro abarcaremos los principales temas que componen la programación orientada a objetos con C++: cuáles son sus características y cómo se utilizan sus funciones. El contenido de cada capítulo es eminentemente teórico, acompañado siempre de diagramas y consejos prácticos.

PROGRAMACIÓN ORIENTADA A OBJETOS

GESTIÓN DE MEMORIA

En este primer capítulo abordaremos

Descubriremos cómo solicitar memoria

los conceptos principales que hacen a la

desde un programa en forma dinámica

programación orientada a objetos y haremos

por medio de los punteros, para hacer

una introducción a los sistemas complejos.

un uso más eficiente de los recursos de la computadora. Veremos también qué son las referencias.

FUNDAMENTOS DE C++ Estudiaremos los elementos que componen este lenguaje de programación y conoceremos sus principales virtudes.

HERENCIA En este capítulo abordaremos herencia y composición, dos recursos fundamentales en el momento de crear el modelo de datos de nuestro sistema. Veremos cómo trabajan los

ASPECTOS AVANZADOS DEL LENGUAJE Aprenderemos a interactuar con el usuario,

constructores y destructores y crearemos una pila y una cola utilizando un array.

veremos qué es un array y cómo emplearlo, y comenzaremos a trabajar con variables que contengan texto. Además, explicaremos cómo crear nuestras propias funciones.

POLIMORFISMO EDUCACIÓN 2.0 Estudiaremos el polimorfismo, tercer gran pilar de la programación orientada a objetos. También veremos mecanismos que

CLASE Y OBJETO

implementa el lenguaje para dar soporte

En este capítulo profundizaremos aspectos

a esta característica: la sobrecarga de

del lenguaje estudiando, básicamente, una

funciones y operadores, los métodos

de sus estructuras principales: la clase.

virtuales y las clases abstractas.

www.redusers.com


5

C++

está formado por una serie de diagramas

OBJETOS PERSISTENTES

que nos ayudarán a diseñar y documentar los

Veremos cómo trabajar con los recursos que

diferentes componentes del sistema.

ofrece C++ para la manipulación de archivos: escritura y lectura de datos binarios, y cuáles

ON WEB

son los pasos a seguir para almacenar el estado de un objeto en y desde un archivo.

ESTRUCTURAS DE DATOS DINÁMICAS Y PLANTILLAS Aprenderemos a implementar una lista enlazada, una lista doblemente enlazada,

PATRONES DE DISEÑO

una pila dinámica y una cola dinámica.

Los patrones de diseño son soluciones

Finalmente, aprenderemos a reimplementar

documentadas a problemas clásicos

todas estas estructuras, pero de modo

surgidos en la construcción de sistemas

independiente del tipo de dato que manejen,

orientados a objetos. En este capítulo,

por medio de las plantillas.

veremos algunos de los patrones más populares que podremos aplicar.

ON WEB LA LIBRERÍA DE PLANTILLAS STL La librería STL es un poderoso aliado a la LENGUAJE UNIFICADO DE MODELADO

hora de codificar sistemas que requieran

Este sistema de notaciones está destinado

estructuras de datos, como arrays, listas,

al modelado de aplicaciones que se

pilas, colas y mapas. En este capítulo

basan, principalmente, en conceptos de la

veremos cómo hacer uso de ella y, así,

programación orientada a objetos. Este sistema

mejorar nuestra productividad.

INFORMACIÓN COMPLEMENTARIA A lo largo de este manual podrá encontrar una serie de recuadros que le brindarán información complementaria: curiosidades, trucos, ideas y consejos sobre los temas tratados. Para que pueda distinguirlos en forma más sencilla, cada recuadro está identificado con diferentes iconos: CURIOSIDADES E IDEAS

ATENCIÓN

DATOS ÚTILES Y NOVEDADES

www.redusers.com

SITIOS WEB


6

PRELIMINARES

Contenido El libro de un vistazo .................................................. 4

Fundamentos de C++

Información complementaria..................................... 5

¿Qué es un lenguaje de programación? ....................30

Introducción ............................................................. 12

Proceso de compilación .........................................30 Proceso de enlace .................................................31 Entornos de programación ....................................31 Un poco de historia ...................................................32

Programación orientada a objetos

Diferencias entre C y C++ .....................................34 Nuestro primer programa en C++.............................34

Introducción ..............................................................14

Comentarios ..........................................................36

Programación no estructurada ..............................15

Variables.....................................................................38

Programación procedural ......................................15

Asignación .................................................................39

Programación modular..........................................16 Programación orientada a objetos.........................16 ¿Qué es un objeto? ................................................17

if

Más características de los objetos .........................19 Aún más características de los objetos...................20 El análisis y el diseño en la programación

( expresión

orientada a objetos....................................................23 El lenguaje unificado de modelado ........................24 Resumen ....................................................................27

) sentencia

Actividades ................................................................28 else sentencia

televisor Entrada video

televisor

Constantes .................................................................41 Tipos de datos fundamentales ..................................42 Números enteros ...................................................42 Números no enteros ..............................................43

dvd

El operador sizeof .................................................45 Caracteres .............................................................46

dvd

El tipo de dato void ...............................................47 Booleanos..............................................................47 Operadores .................................................................47 Precedencia de operadores ...................................49

www.redusers.com


7

C++

Control del flujo de ejecución...................................51 Sentencias condicionales .......................................52 Sentencia de bucle ................................................62 Resumen ....................................................................71 Actividades ................................................................72

Clase y objeto La clase ....................................................................134 Las funciones miembros o métodos .....................137 El diagrama de clases ..............................................145 El diagrama de objetos ...........................................146 El constructor..........................................................147

Aspectos avanzados del lenguaje

El destructor............................................................150

Entrada y salida en C++ ............................................74

Propiedades estáticas..............................................152

El objeto cout ........................................................77

Métodos estáticos ...................................................155

Modificadores de acceso .........................................150

El objeto cin ..........................................................80

Restricciones de los métodos estáticos ................157

El preprocesador .......................................................81

El juego de la vida ...................................................158

Array ..........................................................................84

La resolución .......................................................158

Funciones...................................................................91

La propiedad .......................................................158

Funciones que retornan valores .............................93

Los métodos ........................................................159

Funciones con parámetros .....................................94

La función main...................................................168

Arquitectura de un programa complejo ...............106

Patrones de interés .............................................170

Los string en C++ ....................................................109

Resumen ..................................................................171

Funciones para la manipulación

Actividades ..............................................................172

de cstrings ...........................................................113 Estructuras ..............................................................120 Uso de una estructura..........................................121

Class Foo {

Enumeradores..........................................................126

//…

Enumeradores sin valor numérico asociado .........128 Fijando un valor inicial ........................................130

public:

Resumen ..................................................................131

//…

Actividades ..............................................................132

1 10000 1800

unAuto2 2 30000 1500

Métodos y propiedades públicas

protected: //…

unAuto1

Métodos y propiedades privadas

Métodos y propiedades protegidas

private: //…

Otros métodos y propiedades privadas

public: //…

Otros métodos y propiedades públicas

}

www.redusers.com


8

PRELIMINARES

Gestión de memoria

Herencia

Los punteros ............................................................174

¿Qué es la herencia? ................................................220

Cómo declarar una variable

Métodos inline.....................................................221

tipo puntero .........................................................175

Métodos constantes .............................................223

El operador new..................................................178

Crear subclases ...................................................224

Operador delete...................................................178

Modificadores de acceso en la herencia...............225

Punteros a array..................................................179

El modificador de acceso protected .....................227

Cadenas de texto .................................................184

Invocación de construtores ..................................233

Aritmética de punteros ........................................186

Invocación de destructores ..................................233

Las referencias....................................................191 Los punteros como parámetros de funciones ........................................................192 Los punteros como valor de retorno ....................198 Variables estáticas ..............................................201

5. Extraigo un elemento. Extraemos el último elemento que ingresó en la pila.

Puntero a objetos ....................................................208 Las propiedades ..................................................208 Utilizar la clase Cadena.......................................212 El constructor de copia ........................................213

m_iUltimoElemento

6 3 5 4 9

[5] [4] [3] [2] [1] [0]

Array de objetos ......................................................216 El puntero this .........................................................217

4

Resumen ..................................................................217 Actividades ..............................................................218 Constructores con parámetros .............................234 Composición ............................................................237 // Declaro el puntero y solicito memoria Int * pA = new int;

Ocultar el nombre de un método ............................238

?? pA

Composición vs. Herencia .......................................240

dir. de mem. al número entero

Herencia múltiple ....................................................242 *pA = 50;

El caso del diamante ...........................................243

50 pA

dir. de mem. al número entero

Caso de estudio .......................................................246 Cómo funciona una pila .......................................246

// Libero la memoria solicitada Delete pA;

// ERROR: La siguiente línea podría causar // un error en tiempo de ejecución *pA = 60;

50 pA

50 pA

Cómo funciona una cola.......................................246

dir. de mem. al número entero

dir. de mem. al número entero

Declaración de la clase Array ..............................251 60

Definición de la clase Array .................................252 Declaración de la clase Pila ................................255 Definición de la clase Pila ...................................256 Declaración de la clase Cola ................................258

www.redusers.com


9

C++

Definición de la clase Cola...................................259 Usar la pila y la cola ............................................262 Resumen ..................................................................263

Objetos persistentes

Actividades ..............................................................264

¿Qué es un objeto persistente?...............................302 Manejo de archivos en C++.....................................302 Escritura de un archivo ...........................................303 Lectura de un archivo ..........................................308

Polimorfismo

Lectura y escritura de datos binarios ...................314

¿Qué es el polimorfismo? .......................................266

Almacenar el estado de un objeto ..........................318

Sobrecarga de funciones.........................................266

Objetos con punteros ...........................................322

Parámetros opcionales ........................................271

Resumen ..................................................................325

Sobrecarga de operadores ......................................274

Actividades ..............................................................326

El modificador friend...........................................276 Sobrecarga de operadores unarios ......................279

1. Por medio del método open abrimos el archivo existente.

Operadores que no modifican el estado del objeto .............................................282

bla bla bla ejemplo.txt (archivo) 2. Leemos cierta cantidad de caracteres del archivo y la volcamos en un buffer de memoria.

;Juego

;Jugador

bla bla bla RegistrarJugador()

ejemplo.txt (archivo) bla bla bla EmpezarPartida

szBuf (memoria) RealizarMovida

3. Cerramos el archivo.

bla bla bla

Patrones de diseño ¿Qué es un patrón de diseño? .................................328 Operadores que modifican el estado del objeto ....283

El patrón Singleton .................................................328

Sobrecarga de operadores binarios .....................286

El patrón Método Plantilla......................................330

Métodos virtuales ....................................................288

El patrón Fábrica .....................................................332

Destructores virtuales .............................................297

El patrón Estrategia ................................................334

Resumen ..................................................................299

El patrón Observador ..............................................337

Actividades ..............................................................300

Resumen ..................................................................340

www.redusers.com


10

PRELIMINARES

1. La lista, antes de realizarse alguna modificación.

primer nodo NULL

NULL último nodo

2. Creamos un puntero que apunte al primer nodo de la lista, que es el nodo a extraer.

Lenguaje Unificado de Modelado

pNodoAExtraer

Introducción ............................................................342

primer nodo NULL

NULL último nodo

3. Modificamos el puntero al primer nodo de la lista que apunte al próximo nodo a extraer.

Diagramas de Casos de uso .....................................342

pNodoAExtraer

primer nodo

Diagramas de Clases................................................343 Diagramas de Objetos .............................................344 Diagramas de Secuencia .........................................344

NULL último nodo

NULL 4. Modificamos el puntero del nuevo primero nodo, para que apunte a NULL.

pNodoAExtraer

primer nodo

Diagramas de Estados .............................................346 Diagramas de Colaboración ....................................346

NULL último nodo

NULL NULL

Diagramas de Actividad...........................................347

5. Modificamos el puntero a próximo nodo del nodo a extraer, para que apunte NULL.

pNodoAExtraer

primer nodo NULL

Diagramas de Componentes ...................................348

NULL último nodo

NULL NULL

objeto

objeto anónimo

Listas doblemente enlazadas.....................................20

; CtrlRed

S: Entidad

Pila .......................................................................35 hCom enviar (x)

creación de un objeto temporal

mensaje foco de operación

Cola.......................................................................36

callback

llamada

objeto temporal <<creates>>

; Socket

conectar()

retorno

Plantillas ....................................................................37 Listas doblemente enlazadas con plantillas............47 Pila .......................................................................54 Cola.......................................................................55

enviar(x)

Los iteradores ............................................................55

<<destroy>>

Resumen ....................................................................59

recursión

Actividades ................................................................60 destrucción del objeto

línea de vida

ON WEB

La librería de plantillas STL ON WEB

Estructuras de datos dinámicas y plantillas

La librería STL .............................................................2 Las clases contenedoras..............................................2 La clase vector ........................................................2

Listas enlazadas ...........................................................2

La clase list .............................................................5

¿Qué es una lista enlazada?.....................................2

La clase stack..........................................................8

Implementación de lista enlazada ...........................2

La clase queue ........................................................9

La clase Nodo .........................................................3

La clase map .........................................................10

La clase Lista ..........................................................6

Resumen ....................................................................12

www.redusers.com


12

PRELIMINARES

Introducción Este libro está dirigido principalmente al programador novato y de nivel medio, así como al estudiante o al autodidacta. Los primeros cuatro capítulos son introductorios, y allí explicaremos detalladamente cuáles son los fundamentos del lenguaje, su sintaxis y sus sentencias básicas. También veremos cómo realizar nuestro primer programa. Llegando a la mitad del libro profundizaremos los conceptos relacionados con la programación orientada a objetos. Descubriremos qué es un objeto cuando hablamos de C++ y cómo tratar con él. Si usted es estudiante del nivel terciario o universitario de alguna carrera relacionada con la programación, seguramente encontrará muy útil el capítulo 5, en el que se explican algunos conceptos más avanzados, como la gestión dinámica de la memoria. Por otro lado, si es un programador práctico, tal vez desee utilizar las estructuras de datos de la librería STL; en el apéndice C veremos en detalle cómo emplearla. Entre otros temas, descubriremos qué es un iterador, qué es un contenedor y cómo hacer uso de ellos. Finalizado el libro, será capaz de crear sus propias aplicaciones C++ haciendo uso de las herramientas de diseño adecuadas. Con los conceptos aprendidos y los ejemplos vistos, estará preparado para comenzar a experimentar y realizar diversos proyectos. Todos los temas son tratados a través de diagramas visuales y ejemplos prácticos, en búsqueda de facilitar la comprensión de los conceptos.

www.redusers.com


Programación orientada a objetos En este primer capítulo, comenzaremos por conocer qué es la programación orientada a objetos y en qué puede ayudarnos. También veremos sus conceptos principales, la evolución del diseño y una introducción a la construcción de sistemas complejos.

Introducción ............................ 14

El análisis y el diseño en la

Programación no estructurada......... 15

programación orientada

Programación procedural ................ 15

a objetos................................... 23

Programación modular .................... 16

El lenguaje unificado

Programación orientada a objetos ... 16

de modelado .................................... 24

¿Qué es un objeto? ........................... 17 Más características de los objetos .... 19

Resumen................................... 27

Actividades............................... 28

Aún más características de los objetos ................................... 20

Servicio de atención al lector: usershop@redusers.com


14

1. PROGRAMACIÓN ORIENTADA A OBJETOS

Introducción Queremos utilizar la computadora para resolver problemas, ¿no es así? Podría ser un problema propuesto por un profesor de la facultad en un enunciado, el cálculo del saldo de una cuenta bancaria o la programación de un juego. El asunto es que para esto deberemos trasladar dichos problemas a nuestra PC, y este proceso de traslación implica una abstracción. Tal vez el término resulte extraño, pero desde niños estamos acostumbrados a realizar abstracciones: en aquellos tiempos, a veces jugábamos a ser otra persona situada en otro mundo; incluso la bañera podía convertirse en un mar embravecido. Tales ejemplos no son otra cosa que abstracciones, modelos de una realidad llevada a otro contexto por medio de una operación intelectual. Como decíamos, para trasladar un problema a la PC, también realizamos abstracciones; o sea, debemos crear un modelo simplificado de la realidad tomando los elementos que nos parezcan pertinentes y transformándolos en variables, por ejemplo, dentro de un programa. De este modo, nuestra máquina podrá entenderlo, ejecutarlo y, finalmente, habremos obtenido el resultado que estábamos buscando.

Programa Problema

abstracción

Figura 1. Para introducir un problema en una computadora, debemos realizar un proceso de abstracción. Para esto, sin duda, deberemos acudir a un lenguaje de programación, que no es otra cosa que una herramienta. El lenguaje nos permitirá especificar, a modo de instrucciones, cuáles son los pasos que tendrá que seguir la computadora para resolver el problema. Pero cómo especifiquemos la solución dependerá del modelo de programación que utilicemos. Entonces, lo mejor será repasar un poco los modelos más comunes.

www.redusers.com


15

C++

Programación no estructurada Si no estamos empleando ningún modelo de programación en particular, probablemente estemos programando de modo no estructurado. La programación no estructurada consiste en un programa extenso desarrollado dentro de una función principal que utiliza solo variables del tipo global. Este modo de programación puede ser aceptable para la resolución de problemas triviales; sin embargo, a medida que la complejidad se incrementa, comienza a ser muy engorroso su mantenimiento y el agregado de nuevas características.

Figura 2. En la programación no estructurada es difícil seguir el flujo de ejecución.

Programación procedural La mayor parte de los lenguajes de alto nivel soportan la creación de procedimientos, que son trozos de código que realizan una tarea determinada. Un procedimiento podrá ser invocado muchas veces desde otras partes del programa con el fin de aislar la tarea en cuestión y, una vez que finaliza su ejecución, retorna al punto del programa desde donde se realizó la llamada. Además, cada procedimiento tendrá su propio conjunto de datos, aunque podrá acceder a datos globales y a los pasados como parámetros desde el programa principal o desde otros procedimientos. De esta forma, podemos dividir nuestro problema en problemas más pequeños y, así, llevar la complejidad a un nivel manejable.

programa principal

p1

p2

p3

Figura 3. Programación procedural en programas pequeños o medianos. www.redusers.com


16

1. PROGRAMACIÓN ORIENTADA A OBJETOS

programa principal

p1

p2

p3

p4

p5

Figura 4. Programación procedural en un programa de tamaño mayor.

Programación modular La programación modular va un paso más allá con la creación de procedimientos: los agrupa en módulos según su función. De esta manera, el modelo es apto para sistemas más complejos que requieren programas más extensos. Cada módulo tendrá su propio conjunto de datos, creando un nivel intermedio de datos globales, ya que el conjunto de datos del módulo será global para los procedimientos del módulo, pero inaccesible a los programa principal

procedimientos de otros módulos. De este modo, la representación de un determinado concepto del problema podrá

p1

p3

ser llevado a un módulo; por ejemplo, la manipulación de archivos, donde dentro

p2

p4

del módulo en cuestión existirán distintas funciones para su creación, destrucción, lectura, escritura, etcétera.

p3 Módulo 1

Módulo 2

Figura 5. En la programación modular, cada módulo agrupa procedimientos.

Programación orientada a objetos En la programación orientada a objetos, el concepto de módulo es profundizado y se transforma en un objeto. Además, allí, un programa

www.redusers.com


Fundamentos de C++ En este capítulo haremos una introducción al lenguaje C++, expondremos sus principales virtudes, estudiaremos los elementos que lo componen y cómo crear programas con él.

¿Qué es un lenguaje de

Tipos de datos

programación? ......................... 30

fundamentales........................... 42

Proceso de compilación ................... 30

Números enteros.............................. 42

Proceso de enlace............................ 31

Números no enteros ......................... 43

Entornos de programación ............... 31

El operador sizeof............................ 45 Caracteres ....................................... 46

Un poco de historia ................. 32

El tipo de dato void .......................... 47

Diferencias entre C y C++................ 34

Booleanos ........................................ 47

Primer programa en C++ ........ 34

Comentarios .................................... 36

Variables................................... 38

Operadores ............................... 47 Precedencia de operadores.............. 49

Control del flujo de ejecución. 51

Las palabras

Sentencias condicionales ................. 52

reservadas de C++ ........................... 38

Sentencia de bucle ........................... 62

Asignación................................ 39

Resumen................................... 71

Constantes ............................... 41

Actividades............................... 72

Servicio de atención al lector: usershop@redusers.com


30

2. FUNDAMENTOS DE C++

¿Qué es un lenguaje de programación? Un lenguaje de programación es, principalmente, una herramienta. Por medio de él podremos indicarle a nuestra computadora qué pasos debe seguir para resolver un determinado problema. Estos lenguajes suelen ser clasificados según distintos criterios; uno de ellos es su cercanía al lenguaje realmente comprendido por la plataforma. Los lenguajes de bajo nivel son los más cercanos a la arquitectura de la computadora, y el ensamblador es uno de ellos. Por otro lado, los lenguajes de alto nivel utilizan sentencias similares al lenguaje natural empleado por los seres humanos; de este modo, son más fáciles de aprender y, además, pueden ser trasladados a distintas arquitecturas por no poseer un código íntimamente relacionado con estas. En este grupo se encuentra la mayor parte de los lenguajes, como el C, C++, Pascal, Fortran, Basic, etcétera.

Proceso de compilación Ahora bien, tal vez nos preguntemos cómo es que si programamos utilizando sentencias en lenguaje similar al natural, en cualquiera de los lenguajes conocidos, la máquina puede entenderlo. Para esto, existe un proceso mediante el cual se traduce dicho código a un lenguaje entendible por la computadora.

Proceso de compilación archivo main.cpp

archivo main.obj

archivo dos.cpp

archivo dos.obj

archivo tres.cpp

archivo tres.obj

nuestro programa

Figura 1. Un proyecto está formado por un grupo de archivos de código. Cada archivo de código se compila de manera individual. www.redusers.com


31

C++

A este proceso se lo denomina compilación, y los programas que lo realizan se denominan compiladores. Normalmente cuando nuestro programa crece en cantidad de líneas, el proyecto suele ser dividido en diversos archivos de código.

Proceso de enlace Luego, terminado el proceso de compilación, habremos obtenido una serie de archivos (con terminación obj) que deberemos juntar para crear un archivo ejecutable. El proceso que une estos archivos y les adjunta además otros componentes, según corresponda, se denomina enlace, y el programa que realiza esta función es el enlazador. El archivo de salida a este es un proceso ejecutable.

Proceso de compilación

Proceso de enlazado

archivo main.cpp

archivo main.obj

archivo dos.cpp

archivo dos.obj

archivo tres.cpp

archivo tres.obj

archivo ejecutable

librerías estáticas del sistema (lib) Compilador C++

Enlazador

Figura 2. Procesos de compilación y enlace.

Entornos de programación Parece complicado… ¿Compilar y luego enlazar? ¿Cómo hacemos todo esto? Bueno, podríamos decir que somos afortunados: en la actualidad existen muchos entornos de desarrollo donde todos estos procesos se realizan mediante un simple golpe de tecla. La elección de qué entorno utilizar se deja a criterio del lector. Sin embargo, en el Apéndice B se recomiendan algunos de los más populares para el sistema operativo Microsoft Windows.

www.redusers.com


32

2. FUNDAMENTOS DE C++

Es importante hacer la distinción entre un entorno de desarrollo y un compilador: el entorno es simplemente una aplicación –usualmente, de ventanas– que nos permite gestionar un proyecto de programación de manera sencilla; el entorno de desarrollo, por su parte, utiliza el compilador y el enlazador automáticamente. Además, los entornos modernos colorean distintas palabras de nuestro código en función de las sentencias reconocidas del lenguaje, y esto mejora muchísimo la legibilidad del código. Y existen otras tantas funciones más que realiza el entorno para facilitarnos la vida, como ser:

• Permitir la configuración de los parámetros del compilador y el enlazador de manera sencilla.

• Mostrar el nombre de las estructuras de datos empleadas en nuestro proyecto para poder acceder a ellas fácilmente.

• Facilidades de búsqueda avanzada. • Facilidades de impresión. • Muchos entornos incluyen un depurador integrador para realizar un seguimiento paso a paso de la ejecución de nuestro programa.

Un poco de historia El lenguaje C fue desarrollado en los laboratorios Bell durante la década del 70, y proviene de otro lenguaje llamado B, que a su vez desciende de otro lenguaje llamado BCPL. Inicialmente, el lenguaje C fue desarrollado como un lenguaje de programación para escribir y mantener el sistema operativo UNIX, luego fue expandido para trabajar en otros sistemas. A medida que el lenguaje creció y maduró fue tornándose más popular. Actualmente, sus principales características son:

SIMPLIFICACIÓN Esta división se realiza con la intención de disminuir la complejidad en la organización de nuestro proyecto. Cada uno de estos archivos de código es compilado de manera individual.

www.redusers.com


Aspectos avanzados del lenguaje En este capítulo, aprenderemos a interactuar con el usuario por medio de una terminal de texto. Veremos también qué es un array, comenzaremos a trabajar con variables que contengan texto y crearemos nuestras propias funciones.

Entrada y salida en C++ .......... 74

Funciones para la manipulación

El objeto cout .................................. 77

de cstrings...................................... 113

El objeto cin .................................... 80 ▼ ▼

El preprocesador...................... 81

Array......................................... 84

Estructuras ............................120 Uso de una estructura .................... 121

Enumeradores ........................126 Enumeradores sin valor numérico

Funciones ................................. 91

asociado......................................... 128

Funciones que retornan valores ....... 93

Fijando un valor inicial................... 130

Funciones con parámetros ............... 94 Arquitectura de un programa

Resumen.................................131

Actividades.............................132

complejo ........................................ 106

Los string en C++ ..................109

Servicio de atención al lector: usershop@redusers.com


74

3. ASPECTOS AVANZADOS DEL LENGUAJE

Entrada y salida en C++ El lenguaje C++, al igual que el lenguaje C, no incluye primitivas para realizar opciones de entrada/salida. En su lugar, existen librerías estándar que nos permiten, por ejemplo, escribir en la pantalla o tomar un carácter del teclado, es decir, manipular los flujos de entrada/salida a nuestro gusto. Un flujo (en inglés, stream) no es otra cosa que una secuencia de bytes que provienen de una fuente (flujos de entrada) o van hacia algún destino (flujos de salida). Al utilizar este concepto, C++ se desvincula de cuál sea la fuente o el destino concreto; un flujo de salida podría ser la pantalla o un archivo, y todo se manejaría básicamente del mismo modo. El lenguaje C define inicialmente tres flujos estándar:

• stdin, el flujo de entrada (conectado por defecto a la entrada del teclado); • stdout, el flujo de salida (conectado por defecto a la pantalla de la terminal);

stderr, un flujo de error (también conectado por defecto a la pantalla de la terminal).

teclado

flujos de entrada

pantalla

programa

flujos de salida

archivo

archivo

Figura 1. Flujos de entrada/salida en un programa C++. El lenguaje C++ hereda estos conceptos de C y agrega los siguientes tres objetos globales para manipularlos:

• El objeto cin, para manipular el flujo stdin. • El objeto cout, para manipular el flujo stdout. • El objeto cerr, para manipular el flujo stderr. Para poder utilizar estos objetos, bastará con que incluyamos el archivo de cabecera iostream del siguiente modo:

www.redusers.com


75

C++

#include <iostream>

Además, estos objetos, por estar definidos dentro del conjunto de datos estándar del lenguaje, se encuentran bajo el espacio de nombre std (abreviación de “estándar”). Por lo tanto, siempre debemos anteponer std:: a su uso. Por ejemplo: std::cout << “el texto va aquí”;

En lugar de anteponer siempre std, también podemos especificarlo al comienzo del programa: using namespace std;

Pero… ¿qué es un espacio de nombre? Dentro de una librería, existe una gran cantidad de declaraciones que especifican identificadores para cada tipo de dato. ¿Qué sucedería si utilizáramos un nombre ya existente en una librería para un tipo de dato creado por nosotros? El compilador arrojaría un error, por lo que nosotros deberíamos cambiar el nombre de nuestro tipo de dato. ¿Qué sucedería si deseáramos utilizar dos librerías que declarasen dos identificadores con el mismo nombre? En ese caso, modificar el código sería muy trabajoso, ya que dicha librería no fue escrita por nosotros. A modo de analogía, el lector podría pensar qué sucedería si el sistema de archivos utilizado por su sistema operativo no permitiera la creación de subdirectorios, es decir, si todos y cada uno de los archivos que contuviera su disco duro debiesen estar en el directorio raíz. ¡Sería un problema tener que estar renombrando archivos para que no existan dos con el mismo nombre! Un espacio de nombre (en inglés, namespace) en C++ sería equivalente a un directorio en un sistema de archivos. Así como pueden existir dos archivos con el mismo nombre dentro de dos directorios distintos, pueden existir dos identificadores iguales en distintos espacios de nombres.

www.redusers.com


76

3. ASPECTOS AVANZADOS DEL LENGUAJE

Para declarar una variable dentro de un espacio de nombres en particular, simplemente debemos proceder del siguiente modo: namespace MiEspacioDeNombre { int iMiVariable, }

Por lo tanto, el siguiente listado de c贸digo es incorrecto: int iValor; int iValor;

Pero el siguiente no: namespace Ns1 { int iValor; } namespace Ns2 { int iValor; }

Ahora bien, si queremos utilizar la variable declarada dentro de nuestro programa, tendremos que especificar el espacio de nombre al cual deseamos referirnos; de otro modo, el compilador s贸lo buscar谩 el identificador en el espacio de nombres global. namespace Ns1 { int iValor; } namespace Ns2

www.redusers.com


Clase y objeto Ya hemos realizado una introducción al lenguaje; ahora comenzaremos a ver temas relacionados específicamente con la programación orientada a objetos. Profundizaremos aspectos del lenguaje C++ a partir del estudio de una de sus estructuras principales: la clase.

La clase ..................................134

Las funciones miembros o métodos 137

Métodos estáticos .................155 Restricciones de los métodos estáticos ........................................ 157

El diagrama de clases ............145

El diagrama de objetos..........146

El constructor ........................147

El destructor ..........................150

Modificadores de acceso .......150

Resumen.................................171

Propiedades estáticas............152

Actividades.............................172

El juego de la vida .................158 La resolución ................................. 158 La propiedad.................................. 158 Los métodos................................... 159 La función main ............................. 168 Patrones de interés........................ 170

Servicio de atención al lector: usershop@redusers.com


134

4. CLASE Y OBJETO

La clase Una clase es una estructura de datos. Su objetivo, como el de la estructura (struct), es crear nuevos tipos de datos para ser utilizados en un programa. De hecho, la estructura posee muchísimas similitudes con las clases, especialmente en C++. Recordemos que una estructura nos permite manejar un conjunto de datos como un elemento único. Esto es especialmente útil cuando el conjunto de datos posee una estricta relación entre sí y conforma una entidad. En el capítulo anterior, vimos el ejemplo de un automóvil en el que colocamos unas cuantas propiedades relacionadas con él dentro de una estructura. Una clase nos permite ir un paso más allá; no solo podremos declarar tipos nuevos especificando sus propiedades, sino que podremos incluir funciones que, por supuesto, también estarán muy relacionadas con la entidad en cuestión. Supongamos que deseamos implementar una aplicación en la cual requerimos modelar el concepto de un televisor. Para ello, consideraremos algunas de sus propiedades y estableceremos como regla que las propiedades de sintonía (m_uiCanal) y nivel de sonido (m_uiVolumen) solo deberían poder modificarse cuando el televisor esté encendido (m_bEncendido en verdadero). struct Televisor { bool m_bEncendido;

// Indica si la TV está encendida

unsigned int m_uiCanal;

// Indica sintonía del televisor

unsigned int m_uiVolumen; // Indica nivel de sonido };

Ahora, si deseáramos crear un televisor en nuestra aplicación, deberíamos crear una variable a partir de él del siguiente modo: int main() { Televisor tv1;

www.redusers.com


135

C++

// … }

Siguiendo con el ejemplo, si nuestra intención es cambiar el valor de la propiedad m_uiVolumen, bastaría con escribir: tv1.m_uiVolumen = 10;

Pero esto no siempre podrá ser correcto. Habíamos establecido que el nivel del sonido podría ser modificado cuando el televisor estuviera encendido, por lo tanto, tendríamos que haber codificado: if (tv1.m_bEncendido) tv1.m_uiVolumen = 10;

Entonces, el hecho de que el programador modifique el nivel de sonido cuando el televisor esté apagado queda bajo estricta responsabilidad. ¿Es esto lo que queremos? Pues no. Lo ideal sería poder establecer ciertas reglas en una entidad y que de ningún modo otro programador pudiera alterarlas; en definitiva, algo más parecido a un televisor real, es decir, si no se puede variar el nivel de sonido cuando el aparato se encuentra apagado, como usuarios, nada podemos hacer más que obedecer las reglas. Como una alternativa encaminada a subsanar este problema, podríamos crear una función que modificara el nivel de sonido del aparato, que retorne verdadero si lo ha podido hacer y falso de otro modo:

USO DE REFERENCIAS Como se puede ver en la función ModificarVolumen, para el parámetro Televisor hemos utilizado una referencia en lugar de hacer un pase por valor. Esto es conveniente por dos motivos: - Deseamos modificar el objeto original y no una copia que será finalmente destruida. - Pasar una dirección de memoria es más eficiente que copiar las propiedades de una estructura.

www.redusers.com


136

4. CLASE Y OBJETO

bool ModificarVolumen(Televisor & tv, unsigned int uiVolumen) { if (tv.m_bEncendido) {

tv.m_uiVolumen = uiVolumen; return true;

} else return false; }

Entonces, ahora podríamos utilizar esta función de la siguiente manera: int main() { Televisor tv1; // Modifico el nivel de sonido de tv1 ModificarVolumen(tv1, 10); return 0; }

Es necesario hacer el pase de tv1, ya que podríamos poseer varios objetos del tipo Televisor, y la función requiere saber a qué estructura debe modificar sus datos. De modo análogo, podríamos crear otras funciones relacionadas con el televisor: void Encender(Televisor & tv) { Tv.m_bEncendido = tue; } void Apagar(Televisor & tv) {

www.redusers.com


Gestión de memoria En este capítulo veremos cómo solicitar memoria en forma dinámica por medio de los punteros. De esta manera podremos crear objetos dinámicamente y hacer uso más eficiente de los recursos de la computadora. Veremos también qué son las referencias y cuándo es conveniente utilizarlas sobre los punteros.

Los punteros ..........................174

Puntero a objetos ..................208

Cómo declarar una variable

Las propiedades ............................. 208

tipo puntero ................................... 175

Utilizar la clase Cadena ................. 212

El operador new ............................ 178

El constructor de copia .................. 213

Operador delete ............................. 178 Punteros a array ............................ 179

Array de objetos ....................216

El puntero this .......................217

Resumen.................................217

Actividades.............................218

Cadenas de texto ........................... 184 Aritmética de punteros .................. 186 Las referencias .............................. 191 Los punteros como parámetros de funciones................................... 192 Los punteros como valor de retorno ...................................... 198 Variables estáticas ......................... 201

Servicio de atención al lector: usershop@redusers.com


174

5. GESTIÓN DE MEMORIA

Los punteros Si alguna vez escuchamos hablar de punteros, seguramente la frase fue acompañada de la palabra “difícil”. Sin embargo, no tiene por qué ser así. Un puntero es básicamente una construcción del lenguaje que nos permite obtener más control de la memoria de la computadora. Con él podemos crear objetos en forma dinámica y así utilizar eficientemente los recursos del sistema. Supongamos que deseamos almacenar una cierta cantidad de notas de un alumno en alguna estructura de datos. Si bien ya estudiamos este mismo ejemplo cuando vimos los array, ahora agregaremos un condimento extra: la cantidad total de notas de un alumno sólo se conoce cuando comienza a ejecutarse el programa, y puede variar de ejecución a ejecución. Antes, bastaba con crear un array de una determinada cantidad de elementos y listo, pero ahora, ¿qué haremos? Una solución posible sería crear un array absurdamente grande para que se puedan almacenar todas las notas que sean necesarias en cualquier caso. // Creo un array de un tamaño suficientemente grande int aiNotas[1000];

Pero esta solución tiene dos defectos:

• En algunos casos, podría no existir un máximo posible, es decir, la cantidad de elementos es realmente desconocida y puede ser tanto 5 como 250 o 100 000.

• Realizamos un uso muy poco eficiente de los recursos. Si, por ejemplo, creamos un array de 1000 elementos y luego usamos tan solo 10, estaremos desaprovechando muchísima memoria. Una solución que podríamos imaginar sería crear un array de tamaño especificable durante el tiempo de ejecución. De todas maneras, el compilador exige que el valor encerrado entre corchetes en la definición de un array sea una expresión constante, es decir, un valor conocido en tiempo de compilación. Por esa razón no se permite el siguiente código:

www.redusers.com


175

C++

int iTamArray; cout << “Ingrese el tamaño del array: “; cin >> iTamArray; cout << endl; // La siguiente expresión es INVALIDA, iTamArray no es una expresión constante int aiNotas[iTamArray]; // Sigo trabajando con aiNotas // …

Como excepción a la regla, el compilador gcc 3.2 sí acepta el código anterior. Para poder crear un array en el que su tamaño sea especificado en tiempo de ejecución, tendremos que solicitar memoria en forma dinámica utilizando punteros. Un puntero es una variable que no almacena directamente un dato, sino una dirección de memoria en la que se encuentra el dato en cuestión.

Cómo declarar una variable tipo puntero Supongamos que deseamos crear una variable puntero; para ello, deberemos especificar, como con cualquier otra variable, cuál es su tipo. Veamos: // Una variable puntero a un número entero int * pA;

Notemos que la declaración es muy similar a la de una variable convencional, solo que aquí, por ser un puntero, colocamos un signo asterisco (*) entre el tipo de dato y el identificador. pA es, entonces, una variable que contendrá una dirección de memoria donde habrá un número entero. Sin embargo, ¿en qué posición estará el número entero? Aún no lo hemos determinado, simplemente existe el contenedor de la dirección, pero todavía no se estableció qué

www.redusers.com


176

5. GESTIÓN DE MEMORIA

dirección será; el puntero, como cualquier otra variable, comienza con un valor basura en su interior:

pA

???

Figura 1. Un puntero aún no inicializado. Si en nuestro programa existiese otra variable entera, podríamos establecer que nuestro puntero apuntara a ella del siguiente modo: // Declaro una variable entera convencional y la inicializo en 10 int iUnaVariableEntera = 10; // Declaro un puntero a variable entera int * pA; // Ahora le asigno la dirección de memoria donde se encuentra iUnaVariableEntera // al puntero pA pA = & iUnaVariableEntera;

iUnaVariableEntera (0xFFFF0102) pA (0xFFFF0101)

10

0xFFFF0102

Figura 2. El contenido de la variable será un valor, y el contenido del puntero será una dirección de memoria. Notemos que, para obtener la dirección de memoria que le fue asignada a la variable entera iUnaVariableEntera, utilizamos el operador & (“dirección de”). Ahora es posible modificar el valor de la variable entera no solo por medio de ella, sino también por medio del puntero. Para esto, no deberemos hacer lo siguiente:

www.redusers.com


Herencia En este capítulo abordaremos herencia y composición, recursos fundamentales en el momento de crear el modelo de datos de nuestro sistema. Veremos cómo trabajan los constructores y destructores dentro del mecanismo de herencia y crearemos una pila y una cola utilizando un array.

¿Qué es la herencia? ..............220

Métodos inline ............................... 221

Herencia múltiple ..................242 El caso del diamante...................... 243

Métodos constantes ....................... 223 Crear subclases .............................. 224

Caso de estudio......................246

Modificadores de acceso

Cómo funciona una pila.................. 246

en la herencia ................................ 225

Cómo funciona una cola ................. 246

El modificador de acceso protected 227

Declaración de la clase Array......... 251

Invocación de constructores ........... 233

Definición de la clase Array ........... 252

Invocación de destructores............. 233

Declaración de la clase Pila ........... 255

Constructores con parámetros........ 234

Definición de la clase Pila .............. 256 Declaración de la clase Cola .......... 258

Composición ..........................237

Ocultar el nombre

Definición de la clase Cola ............. 259 Usar la pila y la cola ...................... 262

de un método .........................238

Resumen.................................263

Composición vs. herencia ......240

Actividades.............................264

Servicio de atención al lector: usershop@redusers.com

06 C++.indd 219

26/08/2014 09:08:31 a.m.


220

6. HERENCIA

¿Qué es la herencia? La herencia es un concepto fundamental de la programación orientada a objetos. Por medio de esta característica podremos definir nuestras clases a partir de otras más generales y solo agregar las propiedades y métodos de la especialización. En el Capítulo 1 habíamos hecho una introducción a este tema. Habíamos comentado que el modo en que funcionaba la herencia tenía mucho que ver con la forma en que definimos elementos empleando la tradición aristotélica, es decir, nos basamos en un objeto conocido para luego especificar las diferencias que dan origen al nuevo elemento. Debido a que nuestro sistema será una colección de clases relacionadas entre sí, es muy importante ver cómo estará confirmada su estructura. Por lo general, un diseño pobre genera más problemas que soluciones, ya que los errores se propagan rápidamente y se torna más difícil su expansión y mantenimiento. Volvamos al ejemplo de los dispositivos electrónicos del Capítulo 1. Ahora veremos cómo codificar dicho ejemplo en C++. En principio, nuestro interés era incorporar al sistema la entidad Televisor y la entidad Radio, debido a que son dispositivos electrónicos que poseen características en común, y, gracias a la programación orientada a objetos, podremos realizar el modelo de un modo muy natural. Crearemos una clase llamada DispElectronico, que representará un dispositivo electrónico con características comunes a estos, de modo que luego agregaremos la clase Televisor y la clase Radio, ambas subclases de DispElectronico. Veamos: class DispElectronico { // Indica si el dispositivo se encuentra encendido o apagado bool m_bEncendido; public: // Constructor DispElectronico(); // Enciende el dispositivo void Encender() { m_bEncendido = true; } // Apaga el dispositivo

www.redusers.com

06 C++.indd 220

26/08/2014 09:09:11 a.m.


221

C++

void Apagar() { m_bEncendido = false; } // Indica si el aparato está encendido bool EstaEncendido() cons { return m_bEncendido; } };

Analicemos un poco la declaración anterior, ya que estamos haciendo algo nuevo:

• La clase solo posee una propiedad, que es privada y representa el estado del aparato.

• Además, cuenta con cuatro métodos públicos: el constructor (siempre lleva el mismo nombre que la clase y no posee tipo), un método para “encender” el dispositivo (cambia el valor de la propiedad m_bEncendido), otro para “apagarlo” y, finalmente, un método que retorna el valor de la propiedad (no es posible accederla de otro modo porque es privada).

Métodos inline Los métodos pueden ser definidos dentro de la misma clase. Hasta aquí siempre realizábamos la declaración en un archivo de cabecera (terminación .h): class X { // Declaración del método void m1(); };

Y luego, lo definíamos en un archivo de código fuente (con terminación .cpp): void X::m1() { // … }

www.redusers.com

06 C++.indd 221

26/08/2014 09:09:11 a.m.


222

6. HERENCIA

Pero veamos el siguiente caso: class X { // Declaración del método void m1() { // … } };

Ahora hemos introducido una novedad: la declaración y definición conjunta dentro del cuerpo mismo de la clase. Todo esto, en el archivo de cabecera. Por otra parte, ambas son maneras correctas de definir un método, y su modo de uso es exactamente el mismo. Entonces, ¿cuál es la diferencia? ¿Cuándo usar un modo de definición y cuándo el otro? Los métodos declarados dentro del cuerpo de la clase son del tipo inline, algo que podríamos lograr realizando una definición clásica y anteponiendo esta palabra al tipo: inline void X::m1() { // … }

¿Qué quiere decir esto? Normalmente, cuando realizamos una llamada a una función o método, el compilador debe introducir una serie de operaciones en código ensamblador para el pasaje de parámetros y para resguardar ciertos registros del CPU que serán restablecidos al retorno. Por lo tanto, si estos pasos no estuviesen y el código propio de la función fuera copiado, en lugar de realizar dicha llamada, nos estaríamos ahorrando algunas operaciones que, en cierto tipo de sistemas con funciones muy solicitadas, pueden hacer una diferencia. Las funciones o métodos inline poseen la característica de no ser funciones reales, sino que el compilador se toma el trabajo de

www.redusers.com

06 C++.indd 222

26/08/2014 09:09:12 a.m.


Polimorfismo En este capítulo estudiaremos el polimorfismo, tercer gran pilar de la programación orientada a objetos. También estudiaremos qué mecanismos implementa el lenguaje para dar soporte a esta característica: entre ellos, la sobrecarga de funciones y operadores, los métodos virtuales y las clases abstractas.

¿Qué es el polimorfismo? .....266

Sobrecarga de funciones .......266

Sobrecarga de operadores binarios.......................................... 286

Parámetros opcionales .................. 271

Métodos virtuales ..................288

Sobrecarga de operadores.....274

Destructores virtuales ...........297

Resumen.................................299

Actividades.............................300

El modificador friend ..................... 276 Sobrecarga de operadores unarios.... 279 Operadores que no modifican el estado del objeto........................ 282 Operadores que modifican el estado del objeto........................ 283

Servicio de atención al lector: usershop@redusers.com


266

7. POLIMORFISMO

¿Qué es el polimorfismo? En pocas palabras, el polimorfismo es la habilidad que poseen los objetos para reaccionar de modo diferente ante los mismos mensajes. Un objeto del tipo Puerta, al igual que un objeto de tipo Ventana, podrá recibir el mensaje Abrir; sin embargo, cada uno de ellos reaccionará de modo diferente. En C++ el polimorfismo se encuentra íntimamente relacionado con el mecanismo de sobrecarga y los métodos virtuales. Veamos de qué se trata esto.

Sobrecarga de funciones En lenguajes como el C, es común encontrar librerías que poseen grupos de funciones que realizan la misma tarea pero con distintos tipos de datos en los parámetros. De este modo, si la tarea consiste en mostrar en pantalla el dato pasado como parámetro, podremos encontrarnos con casos como el siguiente: void ImprimirInt(int iNum); void ImprimirChar(char cCar); void ImprimirFloat(float fNum); …

El lenguaje C++ provee un mecanismo mucho más conveniente para realizar la misma tarea. Es posible crear funciones que tengan el mismo nombre y difieran en la cantidad y/o tipo de parámetros. Teniendo esto en cuenta, el ejemplo anterior podría ser reescrito como: void Imprimir(int iNum); void Imprimir(char cCar); void Imprimir(float fNum); …

www.redusers.com


267

C++

Queda claro que este procedimiento es mucho más sensato. De este modo, el programador no deberá recordar el postfijo que conforma el identificador de la función apropiada, ya que todas las funciones se llaman del mismo modo. A esta característica del lenguaje se la denomina “sobrecarga de funciones”. El compilador elige qué versión es la correcta en el momento de realizar la llamada, dependiendo de la cantidad y/o el tipo de parámetros pasados. Todo lo dicho se puede aplicar también a los métodos de una clase, que son, en definitiva, funciones miembros. Como el constructor es, además, un método, haciendo uso de la sobrecarga podríamos crear distintos tipos de constructores y dejar que el compilador seleccione cuál de ellos ejecutar en función del modo en que se crea el objeto. Veamos un ejemplo. Supongamos que deseamos construir una clase que represente un tipo de dato “fecha” (no existente como tipo de dato fundamental en C++): class Fecha { float m_fFecha; public: // … };

La clase almacenará internamente la fecha como cantidad de días desde el 30 de diciembre del año 1899 a la medianoche. Sin embargo, permitirá construir un objeto aceptando otros formatos más amigables para el programador. Veamos: El primer constructor podría no recibir parámetros y fijar la fecha en una arbitraria (por ejemplo, la actual): Fecha();

El segundo podría recibir la fecha en tres parámetros que indiquen día, mes y año respectivamente:

www.redusers.com


268

7. POLIMORFISMO

Fecha (int iDia, int iMes, iAnio);

Un tercer constructor aceptaría la fecha en día, mes, año, hora, minuto y segundo. Fecha (int iDia, int iMes, iAnio, int iHora, int iMin, int iSeg);

Por último, el constructor de copia, que recibirá una referencia constante a un objeto del mismo tipo: Fecha (const Fecha & rFec);

Por lo tanto, la declaración de la clase quedará del siguiente modo: class Fecha { float m_fFecha; public: //

Constructor estándar Fecha(); // Constructor día/mes/año Fecha (int iDia, int iMes, iAnio); // Constructor día/mes/año hh:mm:ss Fecha (int iDia, int iMes, iAnio, int iHora, int iMin, int iSeg); // Constructor de copia

TIPO DE DATO RETORNADO POR FUNCIÓN No es posible crear dos funciones con el mismo identificador que solo difieran en el tipo de dato retornado, debido a que el compilador no podrá distinguir cuándo se desea llamar a una o a otra: bool Foo(int iNum); char Foo(int iNum);

www.redusers.com


Objetos persistentes En este capítulo estudiaremos cómo almacenar y recuperar el estado de un objeto, utilizando los recursos que el lenguaje C++ nos ofrece para la manipulación de archivos.

¿Qué es un objeto

persistente?............................302

Almacenar el estado de un objeto ...........................318 Objetos con punteros ...................... 322

Manejo de archivos en C++ .....302

Escritura de un archivo .........303 Lectura de un archivo .................... 308

Resumen.................................325

Actividades.............................326

Lectura y escritura de datos binarios ............................ 314

Servicio de atención al lector: usershop@redusers.com


302

8. OBJETOS PERSISTENTES

¿Qué es un objeto persistente? Sabemos que el estado de un objeto está compuesto por el valor de todas sus propiedades. Es probable que, en algunos casos, deseemos conservar dicho estado una vez finalizada la ejecución del programa, para poder recuperarlo luego. Entonces, el objeto debería tener la habilidad de escribir y leer el valor de sus propiedades en un medio de almacenamiento no volátil (como por ejemplo, un archivo). Pero para poder entender mejor esto, es necesario que veamos primero cómo manipular archivos con C++.

Manejo de archivos en C++ Al igual que el lenguaje de programación C, C++ no cuenta con primitivas de entrada y salida. Sin embargo, dispone de un conjunto de clases creadas para este fin, conocidas como las clases iostream. Stream se puede traducir como “flujo”, y es en este concepto que se basa el paquete de clases iostream para trabajar con dispositivos de entrada/salida. Utilizando flujos es que el lenguaje logra independizarse en gran medida de dispositivos físicos a los cuales finalmente accede; entonces, enviar datos a un archivo, impresora o pantalla se suscita de forma muy similar. Podríamos pensar el flujo como una construcción programática a la que es posible insertarle y extraerle bytes de modo secuencial y aleatorio. Específicamente hablando de archivos, a medida que invocamos métodos de lectura/escritura, existe un cursor que avanza sobre el archivo de modo que, si en la primera operación de lectura hemos leído, por ejemplo, la primera mitad del archivo, en la segunda operación leeremos la otra mitad. Por otro lado, existen flags (banderas) que mantienen estos objetos e indican el estado en el cual se encuentra el archivo. Cuando lleguemos al final de este, se activará un flag denominado eof (por End Of File; fin de archivo), y así sabremos que no quedan más datos en el recurso. Analicemos su estructura simplificada en la Figura 1. Luego veremos cómo se efectúa la escritura y lectura en un archivo desde C++.

www.redusers.com


303

C++

ios

istream

ostream

ifstream

ofstream

iostream

fstream

Figura 1. Diagrama de clases ios simplificado.

• La clase ios es la clase base de esta estructura; si bien no es una clase abstracta, usualmente no se crean instancias de esta. Simplemente contiene propiedades comunes a flujos de entrada y salida.

• La clase istream deriva de ios y representa un flujo de entrada. • La clase ostram deriva de ios y representa un flujo de salida. • La clase ifstream deriva de istream y se especializa en la lectura de archivos.

• La clase oftream deriva de ostream y se especializa en la escritura de archivos.

• La clase iostream deriva de istream y ostream, por lo tanto, posee ambas interfaces y nos permite manipular un mismo flujo de entrada y de salida.

• La clase fstream deriva de iostream y se encuentra especializada en la manipulación de archivos en modo lectura y escritura.

Escritura de un archivo Para escribir en un archivo, haremos uso de la clase oftream o la clase fstream. De la interfaz de ifstream utilizaremos los siguientes métodos:

www.redusers.com


304

8. OBJETOS PERSISTENTES

• Abrir: el método open de la clase oftream abre un archivo en modo escritura. void open(const char* szName, int nMode = ios::out, int nProt = filebuf::openprot);

Parámetros:

• szName: nombre del archivo. • nMode: modo en que deseamos abrir el archivo. Por defecto, posee un valor asignado, que es ios::out, pero se pueden especificar otros, como ios::binary (si deseamos abrir un archivo en modo binario) ios::nocreate (si no deseamos que el archivo se cree, en caso de no existir), ios::app (si deseamos agregar datos al archivo existente, ya que, de otro modo, eliminará todo su contenido), etcétera.

• nProt: modo de protección del archivo (si se desea abrir el archivo en modo compartido, exclusivo, etcétera).

• Cerrar un archivo: el método close cierra el archivo. void close();

• Verificar si un archivo se encuentra abierto: el método is_open indica si el archivo relacionado con el objeto se encuentra abierto, es decir, si ya se ha invocado el método open de manera satisfactoria. int is_open() const;

Mediante este código, el método retorna un valor distinto de cero si el archivo se encuentra abierto, y, de no ser así, retorna cero.

• Escribir en un archivo: para escribir en un archivo, debemos utilizar métodos de clase ostream, es decir, de la clase padre a ofstream, aunque ciertamente esto es indistinto al programador, ya que un objeto del tipo oftream poseerá la interfaz de dicha clase más las interfaces que se hereden de las clases superiores.

www.redusers.com


Patrones de diseño Los patrones de diseño son soluciones documentadas a problemas clásicos surgidos en la construcción de sistemas orientados a objetos. En este capítulo, veremos algunos de los patrones más populares que podremos aplicar en nuestros programas.

¿Qué es un patrón

El patrón Estrategia ..............334

El patrón Observador.............337

Resumen.................................340

de diseño? ..............................328 ▼

El patrón Singleton ...............328

El patrón Método Plantilla ....330

El patrón Fábrica ...................332

Servicio de atención al lector: usershop@redusers.com


328

9. PATRONES DE DISEÑO

¿Qué es un patrón de diseño? Es común que se presenten problemas similares en diversos contextos en la construcción de sistemas informáticos, para los cuales se han propuesto soluciones que finalmente han sido aceptadas por su eficiencia, robustez y elegancia. Un patrón es exactamente eso: una buena solución documentada a un problema común. Un patrón de diseño posee un nombre, describe un problema para el cual el patrón es aplicable, describe una solución independiente del lenguaje con diagramas (UML) y pseudocódigo (también suele ejemplificar en lenguajes populares como C++, Java y Smalltalk) y, finalmente, informa de consecuencias en la aplicación del patrón (costos y beneficios, ya que, en algunos casos, ciertos patrones son mutuamente excluyentes, y la aplicación de uno u otro varía en función del contexto y el criterio del diseñador).

El patrón Singleton La intención de este patrón es asegurarse de que exista solo una instancia de clase y proveer un modo global de acceder a ella. Tradicionalmente, esto ha sido resuelto de dos maneras: la primera consiste en pasar una referencia o un puntero del objeto en cuestión a cada uno que requiera acceder a sus métodos y propiedades. Esto es muy ineficiente ya que estaremos agregando un nuevo parámetro en la llamada a, probablemente, muchos métodos. La segunda se trata de crear una variable global que pueda ser vista desde todo el programa. Esto es poco elegante y hasta perjudicial en muchos casos, ya que,

LA DESTRUCCIÓN DEL SINGLETON En nuestra implementación, no existe manera de hacerlo; será eliminado por el sistema cuando el programa finalice. Es posible crear un método llamado LiberarInstancia y un contador –también estático–, de modo que se incremente en cada TomarInstancia y se decremente en cada LiberarInstancia (en este último método, cuando el contador es cero, el objeto es destruido).

www.redusers.com


329

C++

por ejemplo, nadie evita que se cree otra instancia del objeto en cuestión y, así, existe la posibilidad de ocasionar un error en la ejecución del programa o de que este no se

Singleton

comporte del modo esperado.

Figura 1. Diagrama de clases del patrón Singleton.

-m_pInstancia -… +TomarInstacion() #Singleton()

El patrón Singleton se basa en una clase que posee, básicamente, un método estático y una propiedad estática. // Archivo .h ----- class Singleton { public: static Singleton * TomarInstancia(); protected: // Constructor Singleton() {} private: static Singleton * m_pInstancia; }; // Archivo .cpp ----- // Inicializo el valor de la propiedad estática Singleton * Singleton::m_pInstancia = 0; // …

La clase cuenta con un método estático que, como tal, puede ser invocado sin la necesidad de crear ningún objeto. Este método, llamado TomarInstancia, debe ser invocado para obtener un puntero al objeto único. Veamos de qué forma implementarlo: Singleton * Singleton::TomarInstancia() {

www.redusers.com


330

9. PATRONES DE DISEÑO

if (!Singleton::m_pInstancia) Singleton::m_pInstancia = new Singleton(): return Singleton::m_pInstancia; }

Como se puede apreciar, existe una sentencia condicional if que verifica el valor de la propiedad estática m_pInstancia. Si su valor es NULL (0), entonces se crea un nuevo objeto y se retorna el valor del punteo a este. Notemos que esta condición solo será cierta en la primera llamada al método, y luego, en toda ocasión, se retornará el mismo puntero. El haber colocado el constructor de la clase como protegido evita que el objeto sea instanciado del modo tradicional; en pocas palabras, el siguiente código causará un error de compilación: Singleton obj;

Para poder acceder a los métodos del Singleton, deberemos codificar: Singleton * pObj = Singleton::TomarInstancia();

El patrón Método Plantilla La tarea de este patrón consiste en definir el esqueleto de un algoritmo en una operación retardando partes de su implementación a subclases. Método Plantilla permite que las subclases redefinan ciertos métodos sin cambiar la estructura del algoritmo. Este patrón puede ser utilizado cuando:

• Ciertos pasos de un algoritmo deben implementarse en subclases. • Cierto código común debe ser colocado en superclases para evitar la duplicación. El código sube a una superclase, y se sobrescriben los métodos que correspondan.

www.redusers.com


Puedes comprar este libro impreso o en formato eBook u optar por algunos de los títulos que conforman la biblioteca USERS. En USERSHOP encontrarás las últimas novedades y material informativo de cada título, que te ayudará a decidir la compra.

¡Recibe promociones semanales exclusivas en tu casilla de correo!

usershop.redusers.com + 54 (011) 4110-8700

usershop@redusers.com


VE IN RS CL GR IÓN D UYE AT IGITA IS L

C++ es un lenguaje orientado a objetos popular, moderno y en constante evolución. A la hora de desarrollar, es la opción más poderosa y robusta que jamás se haya creado. EN ESTE LIBRO APRENDERÁ: Introducción: programación no estructurada, procedural, modular y orientada a objetos. Análisis y diseño. Fundamentos de C++: diferencias con C, variables, palabras reservadas, constantes, booleanos, operadores, sentencias condicionales y bucles. Aspectos avanzados del lenguaje: entrada y salida, objetos cout y cin, preprocesador, array, funciones, strings y enumeradores. Clases y objetos: diagramas, constructor y destructor, modificadores de acceso, propiedades y métodos estáticos. Gestión de memoria: punteros, operadores new y delete, variables estáticas.

Esta obra es una versión revisada del libro C++, publicado en 2004 por esta misma editorial.

Herencia: métodos inline y constantes, subclases, composición vs. herencia. Polimorfismo: sobrecarga de funciones y de operadores, modificador friend, métodos y destructores virtuales.

array

NIVEL DE USUARIO

-m_iCantElementos : int -m_piArray +FijaTam() +FijaValor() +LeerValor() +Limpiar()

Juego

Básico / Intermedio

Jugador

+RegistrarJugador() +EmpezarPartida()

+RealizarMovida() 1

2

CATEGORÍA Desarrollo

pila -m_iUltimoElementos : int +Insertar() +Extraer() +Vaciar() +FijaTam()

cola -m_iPrimerElementos : int -m_iUltimoElementos : int +Insertar() +Extraer() +Vaciar() +FijaTam()

JugadorBot1

JugadorBot2

+RealizarMovida()

+RealizarMovida()

REDUSERS.com

PROFESOR EN LÍNEA

En nuestro sitio podrá encontrar noticias relacionadas y también participar de la comunidad de tecnología más importante de América Latina.

Ante cualquier consulta técnica relacionada con el libro, puede contactarse con nuestros expertos: profesor@redusers.com.

GRATIS

C++ PROGRAMACIÓN ORIENTADA A OBJETOS

El presente libro tiene el doble objetivo de introducirnos y profundizar tanto en lo que se refiere a la programación orientada a objetos, como al lenguaje C++, que será nuestra principal herramienta a la hora de implementar los conceptos teóricos que vayamos estudiando. A lo largo de los distintos capítulos, conoceremos los fundamentos del lenguaje, su sintaxis básica y la manera de escribir el primer programa en él. Además, veremos aspectos avanzados, como el preprocesador, el uso de arrays, funciones, estructuras, espacios de nombre, clases, objetos y gestión de memoria, entre otros. Analizaremos también herencia, polimorfismo, estructuras de datos dinámicas y plantillas.

VERSIÓN DIGITAL

C++ PROGRAMACIÓN ORIENTADA A OBJETOS

TIPOS DE DATOS Y OPERADORES PREPROCESADOR, ARRAYS, FUNCIONES Y STRINGS DIAGRAMAS DE CLASES Y DE OBJETOS HERENCIA Y POLIMORFISMO ESTRUCTURAS DE DATOS DINÁMICAS Y PLANTILLAS

INCLUYE INTRODUCCIÓN A UML

LENGUAJE UNIFICADO DE MODELADO


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.