Manual - Programacion Orientada A Objetos - Ok
Manual - Programacion Orientada A Objetos - Ok
PRESENTA:
Autores
Coordinadores:
Lic. José Azahir Gutiérrez Hernández
Ing. Eduardo Ochoa Hernández
Lic. Filho Enrique Borjas García
Programación orientada a objetos. Copyright © 2013-2014 por CONALEP/CIE. Gral. Nicolás Bravo No. 144, Col.
Chapultepec norte C.P. 58260, Morelia Michoacán, México. Tel/fax: (443) 113-6100 Email:
[email protected]
Registro: CONALEP-LIB-C++-01A
ii
Programa: Profesor escritor, objetos de aprendizaje. Desarrollo de la competencia de la producción de
información literaria y lectura.
Esta obra fue publicada originalmente en Internet bajo la categoría de contenido abierto sobre la URL:
http://www.cie.umich.mx/conalepweb2013/ mismo título y versión de contenido digital. Este es un trabajo de
autoría publicado sobre Internet Copyright © 2013-2014 por CONALEP Michoacán y CIE, protegido por las leyes de
derechos de propiedad de los Estados Unidos Mexicanos. No puede ser reproducido, copiado, publicado,
prestado a otras personas o entidades sin el permiso explícito por escrito del CONALEP/CIE o por los Autores.
Editores:
Ing. Eduardo Ochoa Hernández
Lic. Filho Enrique Borjas García
Quedan rigurosamente prohibidas, sin la autorización escrita de los titulares del “Copyright”, bajo las sanciones
establecidas por la ley, la reproducción total o parcial de esta obra por cualquier medio o procedimiento, comprendidos la
reprografía y el tratamiento informático, y la distribución de ejemplares de ella mediante alquiler o préstamo público.
Registro: CONALEP-LIB-C++-01A
ISBN: En trámite
Impreso en_______________________
Impreso en México –Printed in Mexico
iii
Lic. Fausto Vallejo Figueroa
Gobernador Constitucional del Estado de Michoacán
iv
Estimado estudiante:
Las palabras que sombrean estas páginas, no son simple ciencia dentro del diálogo como depósitos
de datos e información, ni son cuestión de vocabulario o listado de definiciones, son la experiencia
generosa de la comunidad CONALEP Michoacán, esa realidad oculta pero necesaria que respaldó
las tareas de investigación y composición literaria del discurso que integra este libro. Nos referimos
a los profesores, administrativos y sindicatos que hoy convergen en el umbral de la existencia para
apoyar a un grupo de profesores escritores que han creado en el sereno libre, arquitecturas de
conocimientos como un viaje de aprendizaje que exigirá del estudiante, lo mejor de sí mismo ante
la presencia luminosa del texto, ese que pretende enseñarle a caminar con la frente en alto.
Las ideas asociadas en este libro, equivalen a la imaginación lograda en el acto de escribir desde
otros textos, al decodificarlas el estudiante, se le exige más vocabulario para enriquecer su habla y
hacer ver a sus ojos más allá de la estrechez de la información que inunda a la sociedad moderna.
El libro no presenta la superficie de la existencia como cruda observación, procura que su dificultad
incite a perforar la realidad hasta reflexiones que renueven los modos inciertos de dar significado al
mundo. La ciencia, la literatura y la tecnología no las percibimos como mundos incomunicables, los
valores son explícitos caminos que las vinculan entorno al currículo del técnico bachiller. Tienen
estos textos organización de premisas, técnicas, justificaciones, normas, criterios y como Usted se
dará cuenta, también mostrará nuestros límites para seguir haciendo puentes entre las incesantes
creaciones de nuevas fronteras de la investigación científica y técnica. Se pretende que estos libros
sean contenido y no un libro de prácticas escolares, sean la herramienta de complementación para
enriquecer los discursos de la enseñanza-aprendizaje.
Los profesores de CONALEP enfrentan a diario las carencias visibles de medios tecnológicos,
materiales y documentales, sería fácil usar las palabras para señalar hasta el cansancio nuestras
apremias, pero se ha decidido mejor producir libros como testimonios vivos y luminosos que
renueven el rol social de la academia colegiada sensible a la condición social, susceptible de ir
perfeccionándose con la acumulación de esta experiencia literaria, para servir de mejor manera al
enriquecimiento de las competencias necesarias para realizar el sueño de éxito de tantos jóvenes
Michoacanos.
v
Mensaje a la comunidad académica
Se vive una época difícil para los libros, no son momentos de lectura tampoco, sin embargo,
esto no debe ser un motivo para no producir literatura para educar mentes creativas, nuestra
generación considera importante que sea la literatura la que emocione a realizar los grandes
sueños de nuestros jóvenes. Si el libro escrito por mexicanos para mexicanos se perdiera, la
conciencia de nuestra sociedad quedaría en orfandad, congelada de sentido y seríamos
habitantes de un mundo siempre detrás de máscaras en rituales de simulación. Este argumento
presente en El laberinto de la soledad, Octavio Paz nos dice al hombre moderno, seamos
universales sin dejar de ser diferentes. El efecto de producir literatura en una sociedad, es como
dice Steven Pinker, es “sacar los ángeles que llevamos dentro”, es lo mejor de nuestro ser como
oferta de conocimiento y valores al servicio de nuestra sociedad. El efecto Malinche que prefiere
libros de traducción, ocasiona la pérdida de identidad y crear la cultura de producir experiencias
de conocimiento como herencia educativa para nuestros estudiantes. Los aztecas en su derrota
se sintieron abandonados por sus dioses, en el presente si cancelamos que la voz de nuestros
profesores que hablarán desde libros a las nuevas generaciones, es algo equivalente, al negar
que las ideas en su crecimiento son una respuesta sociolingüística económica y democrática de
identidad de una nación. Michoacán es un proyecto histórico de libertad, sin ignorar la realidad
del malestar de la cultura actual, CONALEP desarrolla un programa académico para impulsar
su capacidad y compromiso social para generar las ideas curriculares para enriquecer la
sensibilidad y la imaginación científica, técnica y humanista de su comunidad.
vi
Enfoque por competencias
vii
En toda obra literaria se afirma una realidad
independiente de la lengua y del estilo: la escritura
considerada como la relación que establece el
escritor con la sociedad, el lenguaje literario
transformado por su destino social. Esta tercera
dimensión de la forma tiene una historia que sigue
paso a paso el desgarramiento de la conciencia: de
la escritura transparente de los clásicos a la cada
vez más perturbadora del siglo XIX, para llegar a la
escritura neutra de nuestros días.
viii
Palabra escrita bajo luz
En un mundo cada día con más canales de comunicación, la palabra escrita camina por los
muros que denuncian el drama catastrófico sobre el medio ambiente y sobre el control de
la vida humana; el combustible de esta desesperanza produce apatía profunda por tener
contacto con el mundo de la literatura, esta distorsión moral parece reflejarse entre los que
no quieren sentir responsabilidad ni pensar, dejando a otros su indiferencia al ser
prisioneros de ligeras razones y tirria justificada en la empresa de sobrevivir.
Entre un mar de razones dentro del libro escolar en crisis, se percibe la ausencia de esa
narrativa del cuerpo del texto, misma que alimenta al lector de una experiencia de
conocimiento, su ausencia, es más un mal glosario, de un mal armado viaje literario
científico o de ficción. En esos viajes de libros en crisis, nos cansamos de mirar espacios
vacíos de talento, emociones y sensibilidad para responder a un entorno adverso; son
muchas veces un triunfalismo de autoevaluación y una falsa puerta de una real competencia
para actuar en la realidad. Uno no solo vive, escucha la voz interior de un libro, uno es
fundado en el manejo del lenguaje que explica, crea, aplica o expande los límites del
horizonte de nuestro imaginario actuante en lo real. No vivimos leyendo texto, sino leyendo
el paisaje de una realidad, el libro toma la voz del progreso en una siempre reconstrucción
lingüística del sujeto que explica, transforma y comunica desde los desafíos de su
generación.
La información cruda que tanto rellena los libros grises, oscuros y papel pintado; requiere
ser dotada de conceptos que permitan alimentar al sujeto que toma decisiones, que explora
con paso lento, que mira por dentro del lenguaje y aplica la información que cobra sentido
en la siempre expansión de las ideas.
Escribir un libro es siempre reconstruir un discurso, sus lectores en este discurso son el
puente a un texto profundo que demanda esfuerzo en la reconstrucción de los procesos de
razonamiento y el entretejido del discurso que involucra información de fondo, esas fuentes
que justifican su análisis y poseen significado privilegiado para la comprensión de una
realidad.
El lector puede hacer uso del libro con su propia experiencia y con su autoayuda, al precisar
términos y conceptos para prolongar su horizonte de interpretación, el libro se hace cargo de
ix
la memoria de un plan de estudios, es un discurso de diferentes capas de argumentos, tras
este texto se anuncia un orden de experiencia propuesto para su aprendizaje. El libro está
conformado para jóvenes con memoria sin dolor para nuevas palabras, aborda el olvido
como una deficiencia de interactividad entre el discurso argumentativo y los referentes
conceptuales. Esto es el reto en la producción de los libros CONALEP. La propuesta es una
reconstrucción de una semántica más profunda, como el principal reto del estudiante
técnico bachiller del siglo XXI.
Libro,…
todos te miran,
nosotros te vemos bajo la piel.
x
Prefacio v
Mensaje a la comunidad académica vi
Parte 0
Introducción
Introducción 1
Primera parte
La herencia del paradigma estructurado
o el alma del lenguaje de programación C++
1.1. Historia breve del lenguaje C++ 2
1.2. Primer ejemplo: cout y cin, printf y scanf al estilo C++ 7
1.2.1. El ciclo de desarrollo de software 7
1.2.2. cin, cout y cerr: entrada, salida y error estándar al estilo C++ 13
1.2.3. Una adición al lenguaje: el tipo string 14
1.2.4. El punto de entrada: la función main() 14
1.2.5. Variables, tipos de datos y sufijos de tipo 15
1.2.6. Entrada y salida basada en flujos (streams) y espacios de nombres (namespaces) 17
1.2.7. Conversión entre tipos de datos 19
1.2.8. Expresiones y operadores 20
1.2.9. Más sobre el flujo de salida estándar 23
1.3. Estructuras de control 24
1.4. Proceso de compilación y la estrategia de mejor error al compilar que al ejecutar o,
en otras palabras, C consiente y C++ fastidia 29
Referencias 34
xi
Segunda parte
Funciones
2.1 Introducción 2
2.2 Medidas de tendencia central: media, mediana y moda 3
2.2.1 El ciclo de desarrollo de software 3
2.2.2 Beneficios del diseño modular 13
2.2.3 La declaración using 19
2.2.4 Declaración, definición y prototipos de función 20
2.2.5 Constantes con nombres 23
2.2.6 Arreglos 24
2.2.7 Interacción entre funciones 25
2.2.7.1 Ámbito de una variable: variables globales y locales 26
2.2.7.2 Paso de parámetros: parámetros formales y parámetros reales. Valores de devolución 27
2.2.7.3 Formato de números de punto flotante 28
2.2.7.4 Paso de parámetros por valor y por referencia 30
2.2.8 Paso por referencia y parámetros de referencia 32
2.2.9 Paso de parámetros de tipo arreglo 35
2.2.10 Sobrecarga de funciones 37
Referencias 42
Tercera parte
Introducción a la Programación Orientada a Objetos
3.1. Introducción 2
3.2. Ventajas y desventajas del paradigma estructurado y el orientado a objetos 3
3.3. Objetos y clases 5
3.4. Modelado de objetos 8
3.5. Abstracción 9
3.6. Encapsulación 10
3.6.1. Visibilidad 12
3.7. Paso de mensajes 13
3.8. El lenguaje unificado de modelado (UML – Unified Modeling Language) 15
3.9. Relaciones entre clases 19
3.9.1. Dependencia (utiliza) 18
xii
3.9.2. Agregación (tiene-un) 20
3.9.3. Composición (tiene-un) 22
3.9.4. Herencia (es-un) 23
3.9.4.1. Redefinición o sobrescritura de métodos 25
3.9.4.2. Clases abstractas y métodos abstractos 25
3.9.4.3. El principio de substitución de Liskov 28
3.9.5. Polimorfismo 29
3.10. La cuarta sucesión 40
Referencias 41
Cuarta parte
Implementación de la POO en C++
4.1. Archivos de cabecera 2
4.1.1. ¿Cómo se ubican los archivos de cabecera? 3
4.2. Asignación y liberación de memoria dinámica estilo C++: los operadores new y delete 8
4.3. Creación y empleo de objetos 11
4.3.1. Variables y funciones miembro 12
4.3.2. Constructores y destructores 13
4.3.3. Funciones miembro obtener (getters) y establecer (setters) 15
4.3.4. Implementación de las funciones de una clase 18
4.3.5 Listas de inicialización en los constructores 18
4.4 Relaciones entre clases 23
4.4.1. Tipos de datos de enumeración 25
4.4.2. Constructores explicit y destructores virtual 30
4.4.3. Más de la clase Forma 31
4.4.4. Herencia 35
4.4.4.1. La clase Forma2D 35
4.4.4.2. Llamada de funciones miembro de una clase base desde las funciones miembro de
una clase derivada 38
4.4.4.3. Clases concretas derivadas de la clase Forma2D 38
4.4.4.4. Listas de inicialización en constructores de clases derivadas 41
4.4.4.5. Orden de llamada de constructores y destructores 41
4.4.4.6. Más de la clase Circulo 42
xiii
4.4.4.7. La clase Forma3D 47
4.4.4.8. Clases concretas derivadas de la clase Forma3D 48
4.4.5. Polimorfismo 55
4.4.5.1. Relaciones entre objetos en una jerarquía de herencia 58
4.4.5.2. Utilidad de las funciones virtual 61
4.4.6 Información de tiempo de ejecución (RTTI – RunTime Type Information) y coerción
de tipos descendente dinámica 62
Referencias 65
xiv
2014 [INTRODUCCIÓN]
Capítulo 0. Introducción
… Si los programadores son como (el resto de) los ingenieros, yo debería
poder cambiar un programador por otro y obtener resultados similares
¿no?
--- 1 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN]
Como su nombre lo indica, este proceso es un ciclo, el cual se repetirá tantas veces
como sea necesario, a fin de resolver el problema planteado inicialmente.
--- 2 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN]
1 S. Horstmann, Cay. (2010) C++ for Everyone, 2nd. Ed. New Jersey: John Wiley & Sons, Inc.
2 A. Robertson, Lesley (2004) Simple Program Design: A Step-by-Step Approach, 4th. Ed. Hong
Kong: Course Technology.
3 Fowler, M. & Scott, K. (1999) UML gota a gota. Naucalpan de Juárez, México: Addison-Wesley.
--- 3 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN]
4 A. Weisfeld, Matt. (2009) The Object-Oriented Thought Process, 3rd. Ed. New Jersey: Addison-
Wesley.
--- 4 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
--- 1 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
--- 2 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
i La programación se modela de una forma más cercana al problema del mundo real que se intenta
resolver, por lo que es más fácil de entender para los programadores y, por lo tanto, se aleja más del
modelo entendible por las computadoras.
ii La notación BNF es empleada prácticamente por todos los lenguajes de programación modernos,
a fin de expresar su gramática y para la construcción de sus compiladores y/o intérpretes.
--- 3 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
iii Aún y cuando Simula ya emplea estos conceptos, no lo hace propiamente hablando con los
términos encapsulación y polimorfismo, pero sí herencia.
iv La forma monolítica del software a la que se hace referencia, se debe colocar en el contexto apropiado
de tiempo, el del nacimiento del lenguaje Simula, ya que esta es una de las modificaciones que la
programación estructurada introdujo, que el software se desarrollara en módulos de tamaño
suficientemente manejable y no como tales monolitos.
--- 4 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
--- 5 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
--- 6 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
C++11 de la ISO,4 a The Design and Evolution of C++,5 a la página web del propio
Bjarne Stroustrup6 y a Programming and Practice – Principles and Practice Using
C++.1
normal.
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
viii Esta estrategia busca dividir el problema original en subproblemas más pequeños, de tal manera que
sean más fáciles de resolver; posteriormente, cada subproblema se divide nuevamente en problemas más
pequeños, y así sucesivamente, hasta obtener problemas suficientemente pequeños, que puedan ser
expresados en términos de la computadora utilizada o del pseudocódigo o lenguaje de programación
empleados. Cabe señalar que cada nivel de descomposición en subproblemas, debe ser una solución
completa al problema originalmente planteado.
--- 8 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
La instrucción en pseudocódigo:
IMC ←
Presentar resultados
--- 9 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
FIN SI
debiera comprobar si el IMC < 18.5 pero, dadas las comprobaciones anteriores, esta
es la única opción posible al llegar a este punto del algoritmo. Por tal motivo,
resultaría ineficiente realizar la comprobación explícitamente pero, a fin de recordar
dicha situación, colocamos un comentario que lo indique.
ix Como se verá más adelante, esta es la misma convención que utiliza el lenguaje C++ para definir
comentarios de una sola línea, es decir, el texto escrito después de las dos diagonales (y hasta el
final de la línea) se considera un comentario.
--- 10 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
FIN SI
Llegados a este punto del refinamiento, tenemos ya el detalle suficiente para pasar
a la etapa siguiente del ciclo de desarrollo de software, probar que el algoritmo creado
sea correcto. Para realizar esta etapa, tomaremos ciertos datos de entrada
(pesos y alturas) y calcularemos el resultado manualmente. Posteriormente,
compararemos los resultados calculados contra los resultados que obtengamos de la
ejecución de escritoriox que hagamos del algoritmo, con los mismos datos de prueba.
50 172 IMC: 16.9010 Su IMC es: 16.9010. Cuidado, su peso es demasiado bajo.
x Este es un proceso en el que el programador sigue la lógica del algoritmo paso a paso, tal y como
la computadora lo haría, verificando que cada instrucción realice lo que se supone debe realizar.
Además, se lleva un registro en papel de los valores de las variables más importantes y de todos los
cambios que sufren mientras se sigue el algoritmo.
--- 11 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
80 172 IMC: 27.0416 Su IMC es: 27.0416. Usted tiene sobrepeso, cuide su alimentación.
1. // Listado 1: imc.cpp
2. // Calcula el índice de masa corporal (IMC) de una persona con base
3. // en su peso y altura, y emite un mensaje acorde al resultado.
4. #include <iostream>
5. #include <string>
6.
7. int main(void)
8. {
9. int peso = 0;
10.
11. // Leer datos de entrada
12. std::cout << "Proporcione su peso (kg) sin decimales: ";
13. std::cin >> peso;
14.
15. int altura = 0;
16. std::cout << "Proporcione su altura (cm) sin decimales: ";
17. std::cin >> altura;
18.
19. float altura_metros = altura / 100.0;
20. float IMC = peso / (altura_metros * altura_metros);
21.
22. std::string mensaje = "";
23.
24. if (IMC >= 30.0)
25. {
26. mensaje = "Usted sufre de obesidad, tome medidas precautorias.";
--- 12 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
27. }
28. else
29. {
30. if (IMC >= 25.0)
31. {
32. mensaje = "Usted tiene sobrepeso, cuide su alimentación.";
33. }
34. else
35. {
36. if (IMC >= 18.5)
37. {
38. mensaje = "Felicidades, su peso es normal.";
39. }
40. else // IMC < 18.5
41. {
42. mensaje = "Cuidado, su peso es demasiado bajo.";
43. }
44. }
45. }
46.
47. // Mostrar resultados
48. std::cout << "\nSu IMC es: " << IMC << ". " << mensaje << std::endl;
49.
50. return 0;
51. }
En las líneas 4 y 5 del listado anterior, podemos ver la inclusión de dos archivos
de cabecera de C++. A diferencia del lenguaje C, en C++ es de uso común no
colocar la extensión “.h” característica de este tipo de archivos; el compilador la
añade automáticamente, si no está presente.
1.2.2. cin, cout y cerr: entrada, salida y error estándar al estilo C++
--- 13 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
por <iostream> y, las funciones scanf/printf, por los objetos del flujo de entrada
estándar (cin) y del flujo de salida estándar (cout), en conjunción con los operadores
de extracción de flujo (>>) y de inserción de flujo (<<). Por el momento consideraremos
el término objeto, como un sinónimo de variable, aunque más adelante estableceremos
la diferencia entre ambos. Así también, los descriptores de archivo stdin (la entrada
estándar), stdout (la salida estándar) y stderr (la salida estándar de error) han sido
vueltos a concebir como flujos (streams) de datos, los cuales son, como antes se indica,
manejados por medio de objetos/variables.
está delimitado por los caracteres “{“ y “}”. Esta función, al igual que en C, es el
xi La entrada/salida (E/S) estilo C aún existe, pero se recomienda usar la nueva E/S, estilo C++. De
la misma manera, los archivos de cabecera referentes al lenguaje C, pueden ser utilizados e incluidos
en un programa en C++, con la notación tradicional o, como se aconseja, iniciando con una letra “c”
y sin colocar la extensión “.h”. Así pues, por ejemplo, en un programa en C++ el archivo <stdio.h>
se incluiría como <cstdio>.
--- 14 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
xii Un bloque de código es aquel conjunto de una o varias instrucciones que inicia con el caracter “{”
y termina con el caracter “}”.
xiii Los rangos de valores y tamaños mostrados corresponden a un equipo de cómputo típico con un
procesador de 32 bits. Los archivos de cabecera <climits> y <cfloat> señalan los rangos y
tamaños específicos para cada sistema de cómputo, para los tipos enteros y los de punto flotante,
respectivamente.
--- 15 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
C++ proporciona varios caracteres o sufijos que sirven para indicar el tipo de una
constante que inicializa una variable, es decir, el tipo de un número que se escribe
entero sin signo, l o L para un entero largo, ul o UL para un entero largo sin
xiv Con excepción del tipo de datos int, los tipos integrales pueden omitir en su nombre la palabra
reservada int. Por ejemplo, el tipo puede escribirse como short int o solamente como short.
xv true y false son palabras reservadas del lenguaje C++.
--- 16 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
signo, ll o LL para un entero largo largo y ull o ULL para un entero largo largo sin
signo.
Los sufijos para los tipos de punto flotante son: f o F para un número de tipo
Los ejemplos siguientes emplean sufijos para indicar el tipo de datos pretendido:
La línea 12:
--- 17 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
Empleando una analogía lo anterior quiere decir que, tanto el nombre cout como
todos los nombres que sean precedidos por “std::”, pertenecen a una misma familia,
cuyo apellido es “std”. Es decir, cuando un equipo de trabajo se encuentra
desarrollando un programa, debe definir todos los identificadores que utilizará, pero sin
duplicar ni uno solo de ellos. Así, si sucede que el programador encargado de
desarrollar el código de manejo de archivos utiliza una función “busca()” para
encontrar un dato en un archivo y, el programador encargado de desarrollar el código
de la interfaz gráfica de usuario, también emplea una función “busca()”, pero para
localizar un botón donde el usuario haya dado clic con el ratón; se generará un conflicto
de identificadores cuando el equipo de desarrollo una ambas partes del código. El
programa no podrá determinar cuál de las dos funciones se debe ejecutar cada vez que
encuentre una llamada a la función “busca()”.
Para evitar el problema anterior, C++ crea los espacios de nombre, los cuales
proporcionan un apellido a cada identificador. Así pues, en el ejemplo anterior, el
primer programador podría definir su propio espacio de nombres “archivo” y, el
segundo, “interfaz”; de tal manera que la función “busca()” del primer programador
tendría el nombre “archivo::busca()” y, la del segundo programador, el nombre
“interfaz::busca()”, solucionando el conflicto de nombres.
Entonces, para evitar conflictos entre el propio C++ y los programadores que lo
emplean, el lenguaje les proporciona el apellido “std” (el espacio de nombres
estándar –std) a todos los identificadores que usa, diferenciándolos de los utilizados
por cualquier programador.
En el Listado 1 podemos ver que los nombres pertenecientes a C++ son: cout,
--- 18 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
La fortaleza de la E/S basada en flujos de C++ proviene del hecho de que está
sobrecargada, es decir, que funciona para cualquiera de los tipos de datos básicos.
Por ejemplo, en las líneas 13 y 17 leemos el peso y la altura de una persona como
datos de tipo entero, pero sin indicarlo de manera explícita en momento alguno. C++
sabe qué tipo de dato leer, al ver el tipo de la variable cuyo valor solicitamos desde
el teclado. Lo mismo funciona para la impresión en pantalla de una variable, no es
necesario indicar el tipo de la misma ya que C++ determinará el tipo a imprimir, a
partir del tipo de la variable cuyo valor deseamos presentar en pantalla, por ejemplo
el IMC de tipo float en la línea 48 del Listado 1.
En este sentido, al escribir 100.0 C++ interpreta dicho valor como de tipo
double, por lo que promueve a este tipo de dato también la variable altura y,
--- 19 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
A = 3.1416 * r * r;
xvi Recuérdese que el tipo de cada valor (constante o variable) en una expresión con mezcla de tipos
(expresiones que contienen valores de más de un tipo de datos) se promueve al tipo de datos más grande
(en realidad, se crean versiones temporales de los valores, los datos originales no se alteran). Esto es, si
la expresión contiene un dato de tipo long double, todos los demás valores se promoverán a este tipo;
si contiene un dato de tipo double, todos los demás se convertirán a este tipo; esto sigue aplicándose
siguiendo la secuencia float, unsigned long long int, long long int, unsigned long int,
long int, unsigned int, int, unsigned short int,
short int, unsigned char, char y, finalmente, el tipo de datos bool.
--- 20 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
1
r= r = ((1/2) * a * t * t) + (v0 * t) + (r0);
2 a + v o + r0
s = (a/b) * (c/d);
= ×
--- 21 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
--- 22 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
Cabe señalar que los lenguajes C y C++ cuentan con el operador de coerción
de tipo “(tipo) dato”, pero dado su parecido con la notación de llamadas a
función, entre otros motivos, en C++ se prefiere la utilización del operador
“static_cast<>()”, para señalar la coerción de tipos de manera más explícita.
Para continuar y finalizar el análisis del Listado 1 tenemos que, en la línea 22,
se inicializa la variable mensaje de tipo string con la cadena vacía (“”) y, en la
estructura condicional if de las líneas 24-45, se le asigna a esta variable el texto
resultante de la clasificación del IMC. Para culminar, los resultados obtenidos se
muestran en pantalla (se envían al flujo de salida, representado por el objeto cout,
mediante el operador de inserción “<<”) en la línea 48.
std::cout << "\nSu IMC es: " << IMC << ". " << mensaje << std::endl;
--- 23 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
Secuencia
Descripción
de escape
--- 24 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
return 0;
indica que el valor devuelto por la función main() a quien la llama (el sistema
operativo) será 0, un valor de tipo int como la cabecera de la función en la línea 7
lo señala. Este valor es la convención generalizada para indicar que el programa
terminó de manera satisfactoria y sin problemas.
xvii Esto puede ser importante, por ejemplo, cuando queremos imprimir en pantalla un mensaje
solicitando al usuario que introduzca uno o varios valores.
xviii Permítasenos igualar este término al de programa, aunque esto no sea totalmente preciso.
--- 25 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
La instrucción while.
La instrucción do…while.
La instrucción for.
Por ejemplo, la evolución del desarrollo del programa estructurado del Listado 1
se muestra en las Figuras 3 y 4.
xix La sintaxis de las instrucciones if, if…else, switch, while, do…while y for, es idéntica en
los lenguajes de programación C y C++, razón por la cual no se tratan a detalle en esta obra, pero
se muestran ejemplos de su utilización en cada uno de los programas desarrollados.
--- 27 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
Figura 3. Evolución del desarrollo del programa estructurado del Listado 1. Parte 1 de 2
--- 28 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
Figura 4. Evolución del desarrollo del programa estructurado del Listado 1. Parte 2 de 2
--- 29 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
xx El lenguaje máquina también es conocido como código objeto, código binario o código ejecutable.
--- 30 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
La tercera fase del proceso es, en sí, la traducción a código máquina. En esta
fase se genera un archivo con el mismo nombre del archivo “.cpp”, pero cambiando
la extensión a “.o” o “.obj”, dependiendo del compilador utilizado. La extensión se
debe a que el archivo generado contiene código objeto o binario.
Aún y cuando la tercera fase de la compilación genera código binario, esto es,
código que ya es ejecutable, el uso que los programas realizan de las funciones de la
--- 31 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
Con relación al proceso de compilación, cabe señalar que todo programador que
llega al lenguaje de programación C++, desde el mundo del lenguaje C, encuentra que
el compilador de C++ es muy fastidioso. Genera una cantidad enorme de errores y
advertencias sobre código sospechoso o, aparentemente, mal escrito.
--- 32 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
--- 33 ----
CONALEP MICHOACÁN
2014 [HERENCIA DEL PARADIGMA ESTRUCTURADO]
Referencias
1 Stroustrup, Bjarne. (2009) Programming – Principles and Practice Using C++. Kendallville, Indiana:
Addison-Wesley.
2 Rosenberg, Doug and Scott, Kendall. (2001) Driving design: the problem domain. Dr. Dobb’s.
Consultado: 04 de octubre de 2013, de http://www.drdobbs.com/driving-design-the-problem-
domain/184414689
3 Stroustrup, Bjarne. (2013) The C++ Programming Language, 4th. Edition. Ann Arbor, Michigan:
Addison-Wesley.
4 ISO/IEC 14882:2003. (2003) Programming Languages – C++. The C++ standard.
5 Stroustrup, Bjarne. (1994) The Design and Evolution of C++. Addison-Wesley.
6 Stroustrup, Bjarne. Welcome to Bjarne Stroustrup's homepage! Consulta 09 de octubre de 2013,
de http://www.stroustrup.com/
7 Wikipedia. “Índice de masa corporal.” Consultado: 05 de noviembre de 2013.
http://es.wikipedia.org/wiki/%C3%8Dndice_de_masa_corporal
8 Wirth, N. (1971) Program development by stepwise refinement. Communications of the ACM,
Volume 14, Issue 4, April 1971, Pages 221-227. Consulta 07 de noviembre de 2013, de
http://doi.acm.org/10.1145/362575.362577
9 Böhm, C. & Jacopini, G. (1966) Flow Diagrams, Turing Machines and Languages with Only Two
Formation Rules. Communications of the ACM, Volume 9, Issue 5, May 1966, Pages 366-371.
Consulta 15 de noviembre de 2013, de http://dx.doi.org/10.1145/355592.365646
--- 34 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
Capítulo 2. Funciones
--- 1 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
2.1 Introducción
--- 2 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
--- 3 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
+ + +⋯+ 1
= =
--- 4 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
--- 5 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
Solicitar_datos(datos, numDatos)
Imprimir_datos(datos, numDatos)
Mostrar la media, la mediana y la moda
SI NO
Mostrar “No se introdujeron datos.”
FIN SI
FIN
i Un valor centinela es un valor especial que indica que la introducción de datos, en un programa, ha
terminado. Esto es, mediante una estructura de control de repetición se reciben individualmente
datos hasta el momento en el que se introduce el valor centinela. Por este motivo, el valor centinela
nunca debe ser un valor que se pueda confundir con una entrada válida para el programa.
--- 6 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
Ordenar_datos(datos, numDatos)
PARA i ← 1 HASTA numDatos - 1
HACER minj ← i
--- 7 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
Calcular_mediana(datos, numDatos,
mediana) indiceMediana ← numDatos/2
SI numDatos es impar ENTONCES
mediana ← datos(indiceMediana +
1) SI NO
mediana ← (datos(indiceMediana) + datos(indiceMediana +
1))/2 FIN SI
FIN
elemento
// de un conjunto es el elemento 1, no el elemento 0
Sumar 1 al elemento de frecuencias indicado por
--- 8 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
iMaximo ← 1
Mostrar “ ]”
FIN
El algoritmo, con este tercer refinamiento, está casi completo; lo único que falta
--- 9 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
Solicitar un número entero y validar que sea ≤ 10
Como esta instrucción se emplea más de una vez en el módulo Solicitar_datos,
conviene transformarla, a su vez, en un módulo (función) también. Así, el cuarto
refinamiento del diseño de la solución consiste solamente en definir el módulo
Leer_dato el cual, de acuerdo con el planteamiento del problema, debe recibir un dato
entero entre 0 y 10, o terminar si el dato introducido es < 0. Por tanto, el pseudocódigo
queda del modo siguiente:
Leer_dato(unDato)
HACER
Mostrar “Teclee un entero x, 0 <= x <= 10 (-1 para terminar):
”
Leer unDato
MIENTRAS unDato > 10
FIN
0 moda ← 0
Solicitar_datos(datos, numDatos)
Imprimir_datos(datos, numDatos)
Mostrar la media, la mediana y la moda
--- 10 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
SI NO
Mostrar “No se introdujeron datos.”
FIN SI
FIN
Solicitar_datos(datos,
numDatos) datos ← ø
numDatos ← 0
Leer_dato(unDato)
Leer_dato(unDato)
FIN MIENTRAS
FIN
Leer_dato(unDato)
HACER
Mostrar “Teclee un entero x, 0 <= x <= 10 (-1 para terminar):
”
Leer unDato
MIENTRAS unDato > 10
FIN
Ordenar_datos(datos, numDatos)
PARA i ← 1 HASTA numDatos - 1
HACER minj ← i
--- 11 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
Calcular_media(datos, numDatos,
media) suma ← 0
Calcular_mediana(datos, numDatos,
mediana) indiceMediana ← numDatos/2
SI numDatos es impar ENTONCES
mediana ← datos(indiceMediana +
1) SI NO
mediana ← (datos(indiceMediana) + datos(indiceMediana +
1))/2 FIN SI
FIN
iMaximo ← 1
ENTONCES iMaximo ← i
--- 12 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
FIN SI
FIN PARA
Imprimir_datos(datos, numDatos)
Mostrar “Elementos[”
PARA i ← 1 HASTA numDatos HACER
Mostrar “ ”, datos(i)
FIN PARA
Mostrar “ ]”
FIN
CONALEP MICHOACÁN
2014 [FUNCIONES]
se presenta en la Figura 1.
Llegados a este punto del refinamiento, tenemos ya el detalle suficiente para pasar
a la etapa siguiente del ciclo de desarrollo de software, probar que el algoritmo
creado sea correcto. Como en el capítulo anterior, tomaremos algunos datos de
entrada y calcularemos el resultado manualmente. Después, compararemos los
resultados calculados contra los resultados que obtengamos de la ejecución de
escritorio que hagamos del algoritmo, con los mismos datos de prueba.
Datos de entrada 3, 4, 2, 3, 2, 1, 1, 2, 1, 1, 2, 1, 1
Datos = [ 1 1 1 1 1 1 2 2 2 2 3 3 4 ]
Cálculo manual La media es: 1.85
La mediana es: 2.00
La moda es: 1
Datos = [ 1 1 1 1 1 1 2 2 2 2 3 3 4 ]
La media es: 1.85
Ejecución de escritorio
La mediana es: 2.00
La moda es: 1
--- 14 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
Datos de entrada 3, 4, 3, 2, 1, 1, 2, 1, 1, 2, 1, 1
Datos = [ 1 1 1 1 1 1 2 2 2 3 3 4 ]
Cálculo manual La media es: 1.83
La mediana es: 1.50
La moda es: 1
Datos = [ 1 1 1 1 1 1 2 2 2 3 3 4 ]
La media es: 1.83
Ejecución de escritorio
La mediana es: 1.50
La moda es: 1
--- 15 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
--- 16 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
70.
71. } // solicitarDatos()
72.
73.
74. // Lee un dato de tipo entero <= 10. Un número negativo
75. // finaliza la entrada de datos.
76. // Devuelve el dato leido.
77. int leerDato(void)
78. {
79. int unDato = 0;
80.
81. do
82. {
83. cout << "\nTeclee un entero (-1 para terminar):
84. cin >> unDato; , 0 ≤ x ≤ 10 ";
85.
86. } while (unDato > 10);
87.
88. return unDato;
89.
90. } // leerDato()
91.
92.
93. // Ordena los 'numDatos' primeros elementos de un arreglo
94. // datos: Arreglo a ordenar
95. // numDatos: Número de elementos a ordenar del arreglo
96. void ordenarDatos(int datos[], int numDatos)
97. {
98. for (int i = 0; i < (numDatos - 1); ++i)
99. {
100. int minj = i;
101.
102. for (int j = i + 1; j < numDatos; ++j)
103. {
104. if (datos[j] < datos[minj])
105. {
106. minj = j;
107. }
108.
109. } // for j
110.
111. intercambiar(datos[i], datos[minj]);
112.
113. } // for i
114.
115. } // ordenarDatos()
116.
117.
118. // Intercambia el valor de dos variables
119. // n1: Primera variable a intercambiar
120. // n2: Segunda variable a intercambiar
121. void intercambiar(int& n1, int& n2)
122. {
123. int temp = n1;
124. n1 = n2;
125. n2 = temp;
--- 17 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
126.
127. } // intercambiar()
128.
129.
130. // Calcula la media de los elementos de un arreglo
131. // datos: Arreglo de elementos cuya media se va a calcular
132. // numDatos: Número de elementos del arreglo cuya media se calculará
133. double calcularMedia(int datos[], int numDatos)
134. {
135. double suma = 0.0;
136.
137. for (int i = 0; i < numDatos; ++i)
138. {
139. suma += datos[i];
140.
141. } // for i
142.
143. return (suma / numDatos);
144.
145. } // calcularMedia()
146.
147.
148. // Calcula la mediana de los elementos de un arreglo
149. // datos: Arreglo de elementos cuya mediana se va a calcular
150. // numDatos: Número de elementos del arreglo cuya mediana se calculará
151. double calcularMediana(int datos[], int numDatos)
152. {
153. double mediana = 0.0;
154. int indiceMediana = numDatos / 2;
155.
156. if ((numDatos % 2) == 1) // El número de datos es impar
157. {
158. mediana = datos[indiceMediana];
159. }
160. else // El número de datos es par
161. {
162. double suma = static_cast<double>(datos[indiceMediana - 1] +
163. datos[indiceMediana]);
164. mediana = suma / 2;
165. }
166.
167. return mediana;
168.
169. } // calcularMediana()
170.
171.
172. // Calcula la moda de los elementos de un arreglo
173. // datos: Arreglo de elementos cuya moda se va a calcular
174. // numDatos: Número de elementos del arreglo cuya moda se calculará
175. int calcularModa(int datos[], int numDatos)
176. {
177. int frecuencias[11] = {0};
178.
179. // Contar las ocurrencias de cada valor
180. for (int i = 0; i < numDatos; ++i)
--- 18 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
181. {
182. ++frecuencias[ datos[i] ];
183.
184. } // for i
185.
186. int iMaximo = 0;
187.
188. // Buscar la moda
189. for (int i = iMaximo + 1; i < 11; ++i)
190. {
191. if (frecuencias[iMaximo] < frecuencias[i])
192. {
193. iMaximo = i;
194. }
195.
196. } // for i
197.
198. return iMaximo;
199.
200. } // calcularModa()
201.
202.
203. // Imprime en pantalla los elementos de un arreglo
204. // datos: Arreglo a imprimir
205. // numDatos: Número de elementos a imprimir del arreglo
206. void imprimirDatos(int datos[], int numDatos)
207. {
208. cout << "\nDatos = [";
209.
210. for (int i = 0; i < numDatos; ++i)
211. {
212. cout << " " << datos[i];
213.
214. } // for i
215.
216. cout << " ]" << endl;
217.
218. } // imprimirDatos()
--- 19 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
En C++ las funciones deben ser conocidas antes de su primer uso. En el Listado 2, la
función main hace uso de la función solicitarDatos, por lo tanto, esta debe ser
conocida antes de que se utilice. Para resolver este problema en el ejemplo del
Listado 2, podríamos poner la definición de la función solicitarDatos antes de
la definición de la función main, lo cual resolvería la cuestión planteada.ii El
problema difícil viene cuando tenemos una función evaluaExpresion que hace
uso de una función evaluaSubexpresion la cual, a su vez, emplea a la propia
función evaluaExpresion. Por ejemplo, si tenemos (1 * 2) + (3 – 3),
ii La definición de una función consiste del código fuente que la implementa, es decir, el encabezado
de la función más el conjunto de instrucciones que conforman su cuerpo, delimitado por las llaves
de apertura (“{”) y cierre (“}”).
--- 20 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
Cada función debe ser conocida antes de su primer uso, entonces, si aplicamos la
solución anteriormente descrita y ponemos la definición de la función
evaluaSubexpresion antes de la definición de evaluaExpresion, tal y como
muestra el Listado 3, la llamada que realiza main en la línea 23 es correcta, puesto que
evaluaExpresion es conocida en este punto del código. Luego, la llamada que
realiza evaluaExpresion en la línea 14 también es correcta, puesto que
evaluaSubexpresion ya es conocida en este punto del código fuente. El
inconveniente viene con la llamada que realiza la función evaluaSubexpresion
--- 21 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
--- 22 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
28. }
Volviendo al Listado 2, las líneas 10 a la 17 declaran los prototipos de las funciones que
el programa requiere y cuya definición se proporciona más adelante.
--- 23 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
2.2.6 Arreglos
dentro de una cadena colocada entre comillas-, la reemplace con la cadena texto_de_reemplazo. Así,
el compilador nunca recibe la cadena TEXTO sino texto_de_reemplazo, y ésta es la que formará parte
del proceso de compilación y, por lo tanto, del programa ejecutable generado.
--- 24 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
--- 25 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
La otra forma de variables son las locales, el ámbito de una variable local es
solamente la función en donde se encuentra definida, empiezan a vivir cuando la
función es llamada y mueren cuando la función termina. Este tipo de variable evita
el acoplamiento entre funciones y los efectos colaterales, como la modificación por
error de una variable global. En la medida de lo posible, es el de tipo de variable
que debemos emplear, exceptuando al momento de enviar y recibir información
hacia una función, en ese caso debemos emplear el paso de parámetros y los
valores de devolución.
--- 26 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
En la introducción del capítulo se menciona que cuando una función llama o emplea
los servicios de otra, la función que llama puede enviar información a la función
llamada así como recibir, también, un valor devuelto por esta. La función que
requiera información para realizar su tarea (o que devuelva un valor), debe
especificarlo en su propio encabezado, como una lista de datos a los que se les
denomina parámetros formales o, simplemente, parámetros (una función solo
puede devolver un valor en específico a la función que la llama, por lo que no
requiere una lista, aunque este valor puede ser una estructura de datos constituida
por más de un valor).
En C++ la lista de parámetros formales incluye el tipo de cada dato requerido así
como la asignación de un nombre, esto porque los valores que la función recibe en
realidad actúan como variables locales,iv las cuales se pueden manipular dentro de
la función (lo cual no se aconseja) cuando esta esté en ejecución. Estos valores,
que son los que en realidad se pasan a la función, reciben el nombre de parámetros
reales o argumentos. Por ejemplo, en la línea 111 del Listado 2, los elementos
datos[i] y datos[minj] son los parámetros reales para la función
intercambiar; mientras que, en la línea 121, los parámetros formales de esta
función son n1 y n2.
--- 27 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
Después de ordenar los datos, en las líneas 31 a 35 la función main llama a las
funciones correspondientes al cálculo de cada medida de tendencia central
(calcularMedia, calcularMediana y calcularModa), las cuales devuelven el
valor respectivo a su cálculo. Las dos primeras funciones devuelven un valor de tipo
double, ya que calcularMedia realiza una división cuyo resultado,
generalmente, no será un número entero; y, calcularMediana, debido a que si el
número de elementos en el arreglo datos es par, se tendrán que promediar los dos
valores centrales del arreglo. calcularModa devuelve el valor que más se repite
en el arreglo datos, por tanto, devuelve un valor de tipo entero.
--- 28 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
iomanip.
--- 29 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
Cuando un dato de alguno de los tipos fundamentales se pasa a una función, C++
primero crea la variable correspondiente al parámetro formal, luego realiza una copia
del valor del parámetro real y la asigna al parámetro formal. Esto se denomina paso de
parámetros por valor y sirve para proteger de modificaciones accidentales a la variable
original (el parámetro real) en la función que llama. Aunque esto es lo deseable, en
ciertas circunstancias no es lo que se pretende. Por ejemplo, la función ordenarDatos
(líneas 93 a 115 del Listado 2) procesa todos los elementos del arreglo datos,
ordenándolos de menor a mayor. Para tal efecto se apoya de la función intercambiar
(líneas 118 a 127), cuyo objetivo es colocar el valor de su primer argumento en el
segundo, y colocar el valor de su segundo argumento en el primero. La primera solución
que se nos viene a la mente es codificar esta función como se ejemplifica en el Listado
5. Además, la salida del programa es la siguiente:
1. // Listado 5: pasoporvalor.cpp
2. // Demuestra el paso por valor de argumentos a funciones.
3. #include <iostream>
4. #include <string>
5.
6. using namespace std;
7.
8. // Prototipos de función
9. void imprimirValores(string mensaje, int var1, int var2);
10. void intercambiar(int n1, int n2);
11.
12. int main(void)
13. {
14. int valor1 = 15;
15. int valor2 = 20;
16.
17. imprimirValores("- main(): Antes del intercambio -",
18. valor1, valor2);
19.
20. intercambiar(valor1, valor2);
21.
22. imprimirValores("- main(): Realizado el intercambio -",
23. valor1, valor2);
24.
25. return 0;
26.
27. } // main()
28.
29.
--- 30 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
--- 31 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
Ya vimos que el paso por valor tiene el efecto (a veces bueno, a veces malo) de no
modificar el valor de los parámetros reales. Otro inconveniente es que la copia que
se realiza puede llegar a consumir un tiempo considerable si se pasa como
parámetro de una función, por ejemplo, una variable de estructura o un objeto (que
se tratará en los capítulos siguientes) muy grande, o también, si la llamada a la
función (y, por ende, la copia de un valor de un tipo básico) se realiza dentro de un
ciclo que se repite una gran cantidad de ocasiones.
Para resolver los dos problemas anteriores, el paso de parámetros por referencia
emplea variables de apuntador. Estas variables cumplen con todas las características
de cualquier variable normal, la diferencia consiste en que en lugar de mantener un
valor en específico, mantienen la dirección en la memoria de la computadora en donde
se ubica otra variable.vi Así, cuando se pasa un apuntador como parámetro a una
función, solo se pasa este y no una copia completa de la variable original (cuya dirección
guarda el apuntador, es decir, la variable a la que apunta el apuntador). También se
resuelve la necesidad de modificar el dato original, como el apuntador
vi De ahí el nombre de paso de parámetros por referencia, es decir, lo que se pasa a la función es una
referencia de la ubicación del parámetro real.
--- 32 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
--- 33 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
26. return 0;
27.
28. } // main()
29.
30.
31. // Imprime en pantalla el valor de dos variables enteras
32. // mensaje: Mensaje a imprimir antes de los valores de las variables
33. // var1: Primera variable a imprimir
34. // var2: Segunda variable a imprimir
35. void imprimirValores(string mensaje, int var1, int var2)
36. {
37. cout << "\n" << mensaje;
38. cout << "\nLa primera variable tiene el valor: " << var1
39. << "\nLa segunda variable tiene el valor: " << var2
40. << endl;
41.
42. } // imprimirValores()
43.
44.
45. // Intercambia el valor de dos variables
46. // n1: Primera variable a intercambiar
47. // n2: Segunda variable a intercambiar
48. void intercambiar(int& n1, int& n2)
49. {
50. imprimirValores("- intercambiar(): Antes del intercambio -",
51. n1, n2);
52.
53. int temp = n1;
54. n1 = n2;
55. n2 = temp;
56.
57. imprimirValores("- intercambiar(): Realizado el intercambio -",
58. n1, n2);
59.
60. } // intercambiar()
--- 34 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
A primera vista pareciera que siendo un parámetro que es una colección de datos de
tipo básico, debiera aplicársele el paso de parámetros por valor, lo que implicaría que
las funciones que alteran el contenido del arreglo lo harían en una copia de este, no en
el original y, por lo tanto, que dichas funciones no cumplen con su objetivo. La realidad
es que, en virtud de que el arreglo es una colección de datos cuya copia pudiera
consumir un tiempo excesivo, C++ aplica por defecto a los arreglos el paso de
parámetros por referencia. Esto es, el nombre del arreglo realmente es un apuntador a
su primer elemento, además de que el resto de elementos siempre se almacenan
consecutivamente al primero. Así pues, conociendo la ubicación en memoria del primer
elemento, podemos conocer la ubicación de todos los demás.
Por este motivo, en el encabezado (y el prototipo) de la función que recibe como
solo se indican los corchetes “[]”. La única diferencia entre el nombre de un arreglo
--- 35 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
En las líneas 130 a 145, 148 a 169 y 172 a 200, se encuentra el código de las
funciones calcularMedia, calcularMediana y calcularModa,
respectivamente, las cuales realizan el cálculo de la medida de tendencia central
correspondiente. Las dos primeras se explican por sí solas, el cálculo de la moda
consiste de dos pasos: en el primero se ocupa un arreglo de once elementos, los
necesarios para almacenar la frecuencia de cada uno de los valores que el usuario
puede introducir al programa (0, 1, 2, 3, 4, 5, 6, 7, 8, 9 y 10) y, conforme se recorren
todos los elementos del arreglo de los datos introducidos por el usuario, se van
incrementando las veces que aparece cada uno de ellos (en el arreglo de
frecuencias); el segundo paso consiste en encontrar en el arreglo de frecuencias
cuál es la mayor, dicha frecuencia señala al valor entre 0 y 10 que es la moda.
Finalmente, en las líneas 203 a la 218 del Listado 2, se encuentra el código que
--- 36 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
--- 37 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
- Suma int -
La suma de 10 y 20 es: 30
- Suma float -
La suma de 10.00 y 20.00 es: 30.00
- Suma double -
La suma de 10.00 y 20.00 es: 30.00
C++ facilita la semántica de este tipo de funciones permitiendo que todas las
funciones que queramos puedan llevar el mismo nombre. El único requisito es que
--- 38 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
las funciones tengan una firma diferente. La firma de la función se conforma con el
número, los tipos y el orden de los parámetros (además del nombre de la función, por
supuesto). El tipo de dato que devuelve la función no se considera como parte de la
firma, por lo que dos funciones que solo se diferencien en este detalle, generarán un
error de compilación. El Listado 8 presenta un ejemplo de la sobrecarga de funciones
en C++ y, la salida del programa, se muestra a continuación de él:
1. // Listado 8: sobrecarga.cpp
2. // Demuestra la sobrecarga de funciones en C++
3. #include <iostream>
4. #include <iomanip>
5.
6. using namespace std;
7.
8. // Prototipos de función
9. int suma(int a, int b);
10. int suma(int a, int b, int c);
11. float suma(float a, float b);
12. float suma(float a, float b, float c);
13. double suma(double a, double b);
14. double suma(double a, double b, double c);
15.
16.
17. int main(void)
18. {
19. int i1 = 10;
20. int i2 = 20;
21. int i3 = 30;
22.
23. cout << "\n- Suma int -\nLa suma de " << i1 << " y "
24. << i2 << " es: " << suma(i1, i2);
25.
26. cout << "\nLa suma de " << i1 << ", "
27. << i2 << " y " << i3 << " es: "
28. << suma(i1, i2, i3) << endl;
29.
30. float f1 = 10.0F;
31. float f2 = 20.0F;
32. float f3 = 30.0F;
33.
34. cout << "\n- Suma float -\nLa suma de "
35. << setprecision(2) << fixed << f1 << " y "
36. << f2 << " es: " << suma(f1, f2);
37.
38. cout << "\nLa suma de " << f1 << ", "
39. << f2 << " y " << f3 << " es: "
40. << suma(f1, f2, f3) << endl;
41.
42. double d1 = 10.0;
43. double d2 = 20.0;
44. double d3 = 30.0;
45.
--- 39 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
46. cout << "\n- Suma double -\nLa suma de " << d1 << " y "
47. << d2 << " es: " << suma(d1, d2);
48.
49. cout << "\nLa suma de " << d1 << ", "
50. << d2 << " y " << d3 << " es: "
51. << suma(d1, d2, d3) << endl;
52.
53. return 0;
54.
55. } // main()
56.
57.
58. // Suma dos números enteros
59. // a: Primer número a sumar
60. // b: Segundo número a sumar
61. int suma(int a, int b)
62. {
63. return (a + b);
64.
65. } // suma()
66.
67.
68. // Suma tres números enteros
69. // a: Primer número a sumar
70. // b: Segundo número a sumar
71. // c: Tercer número a sumar
72. int suma(int a, int b, int c)
73. {
74. return (a + b + c);
75.
76. } // suma()
77.
78.
79. // Suma dos números de tipo float
80. // a: Primer número a sumar
81. // b: Segundo número a sumar
82. float suma(float a, float b)
83. {
84. return (a + b);
85.
86. } // suma()
87.
88.
89. // Suma tres números de tipo float
90. // a: Primer número a sumar
91. // b: Segundo número a sumar
92. // c: Tercer número a sumar
93. float suma(float a, float b, float c)
94. {
95. return (a + b + c);
96.
97. } // suma()
98.
99.
100. // Suma dos números de tipo double
101. // a: Primer número a sumar
--- 40 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
- Suma int -
La suma de 10 y 20 es: 30
La suma de 10, 20 y 30 es: 60
- Suma float -
La suma de 10.00 y 20.00 es: 30.00
La suma de 10.00, 20.00 y 30.00 es: 60.00
- Suma double -
La suma de 10.00 y 20.00 es: 30.00
La suma de 10.00, 20.00 y 30.00 es: 60.00
--- 41 ----
CONALEP MICHOACÁN
2014 [FUNCIONES]
Referencias
1 Deitel, P. & Deitel, H. (2014) C++ How to Program, 9th. Ed. Boston, Massachusetts: Pearson
Education, Inc.
2 S. Horstmann, C. & A. Budd, T. (2009) Big C++, 2nd. Ed. New Jersey: John Wiley & Sons, Inc.
3 Savitch, W. (2013) Absolute C++, 5th. Ed. Boston, Massachusetts: Pearson Education, Inc.
4 E. Walpole, R. & H. Myers, R. & L. Myers, S. & Ye, K. (2012) Probabilidad y estadística para
ingeniería y ciencias, 9ª Ed. Naucalpan de Juárez, Estado de México: Pearson Educación de México,
S. A. de C. V.
5 Brassard, G. & Bratley, P. (1997) Fundamentos de algoritmia. Madrid, España: Pearson Prentice-Hall.
6 A. Robertson, Lesley (2004) Simple Program Design: A Step-by-Step Approach, 4th. Ed. Hong
Kong: Course Technology.
7 S. Malik, D. (2012) C++ Programming: Program Design Including Data Structures, 6th. Ed. Boston,
Massachusetts: Cengage Learning.
8 Liberty, J. & Jones, B. (2005) Teach Yourself C++ in 21 Days, 5th. Ed. Indianapolis, Indiana, USA:
Sams Publishing.
9 J. Bronson, G. (2007) C++ para ingeniería y ciencias, 2ª Ed. México, D. F.: Cengage Learning
Editores, S. A. de C. V.
--- 42 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
--- 1 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
3.1. Introducción
En nuestro caso, el paradigma estructurado definió una forma de pensar con relación a
la forma en que el desarrollo de software se debía enfocar, enfrentar, analizar, realizar
y evolucionar. Esta forma nueva de hacer las cosas, logró impulsar la programación de
computadoras en la década de los 70’s, más adelante seguirían manteniendo la fiebre
estructurada el diseño estructurado y el análisis estructurado. Desafortunadamente, con
--- 2 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
1, , , , , , , , ,
c) 1, 4, 9, 16, 25, 36, 49, 64, 81, 100
d) 5, 4, 10, 2, 9, 8, 6, 7, 3, 1
Seguramente, los tres primeros incisos te habrán resultado fáciles de resolver. Cada
uno de ellos implica la multiplicación, suma, división o resta de algún número al
anterior en la secuencia, pero no así a la sucesión del cuarto inciso. Esto es porque
el paradigma creado por las sucesiones en los tres primeros incisos, no es el
adecuado para resolver la cuarta sucesión.
Esta dificultad que se presenta para romper nuestro modelo de pensamiento actual, es
la misma que se presenta cuando un desarrollador de software, acostumbrado al
paradigma estructurado, enfrenta al momento de abordar el paradigma orientado a
objetos. Sin embargo, una vez superado este obstáculo, las ventajas de la
programación orientada a objetos, sobre la estructurada, comienzan a ser evidentes.
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
Las ventajas del paradigma orientado a objetos están referidas a subsanar las
deficiencias anteriores:6
Reúso: las clases bien diseñadas, de origen, son componentes que se pueden
compartir y reutilizar.
Estabilidad: debido a las características de abstracción y de encapsulación y
ocultamiento de información,i las clases y los objetos son partes
intercambiables de software. Solo deben mantener la interfaz pública de
servicios.
Confiabilidad: dado que los componentes individuales de un programa
orientado a objetos son menos complejos que los de un programa que
implementa exclusivamente el paradigma estructurado, la depuración y el
mantenimiento de ellos es más simple, lo que conlleva mayor facilidad para
encontrar y eliminar errores y, por consecuencia, mayor confiabilidad integral
del software.
Integridad: la encapsulación y el ocultamiento de información mantienen la
protección de los datos que pertenecen a cada objeto, lo cual redunda en la
integridad de los mismos.
Modelado iterativo: el paradigma orientado a objetos permite modelar un
número pequeño de clases, luego probar el software, hacer los cambios
necesarios, si se requieren, e iterar este procedimiento tantas veces como sea
necesario hasta finalizar el desarrollo.
--- 4 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
El Diccionario de la lengua española define la palabra objeto como todo lo que puede
ser materia de conocimiento o sensibilidad de parte del sujeto, incluso este mismo.7 Los
objetos pueden ser muchas cosas; cosas tangibles o concretas como autos, clientes,
perros, etc.; cosas intangibles o conceptuales, que son más difíciles de captar o
entender, como transacciones, órdenes de compra, demandas judiciales, etc.; y cosas
que representan eventos y estados, como fechas, nacimientos, graduaciones, partidas,
arribos, aprobaciones, etc.5 Con relación a la POO, un objeto
8, 9,
se define como todo aquello que cuenta con estado, comportamiento e identidad.
10, 11, 12, 13, 14, 15
--- 5 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
Atributo Valor
Semestre 4
Calificaciones 10, 9, 8, 6, 9
Un objeto es como una variable sofisticada que almacena datos y que puede enviar
y recibir mensajes a y desde otros objetos.ii En la POO todo es un objeto, incluso
un programa es un grupo de objetos enviándose mensajes entre sí, para solicitar u
ordenar lo que hay que hacer.
ii Un mensaje es una petición para ejecutar un método (función) que pertenece a un objeto en
particular.
--- 6 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
Y, como se acaba de mencionar, todo objeto debe tener un tipo. En la POO, el tipo de
un objeto es sinónimo de clase. Los objetos que son idénticos, excepto por su estado,
se agrupan en clases de objetos.5 En otras palabras, una clase es un conjunto de
objetos que comparten una estructura común y un comportamiento común. 8, 9, 10,
11, 12, 13, 14, 15, 16
Por tanto, la definición de una clase debe incluir:
Las operaciones permitidas sobre los objetos de la clase, y
Los estados permitidos para los objetos de la clase.
En el diseño de las clases también se debe considerar que todos los aspectos ensamblen
apropiadamente. En otras palabras, las clases deben tener un alto grado de cohesión. La
cohesión significa que la clase tiene la responsabilidad de realizar una y solo una cosa, y
que tanto sus atributos como sus métodos sustentan esa tarea.5
--- 7 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
Como consecuencia de todo lo anterior, un objeto es una instancia de una clase. Por
ejemplo, cuando una alumna nueva, Sandra, ingresa a uno de los planteles del
CONALEP, se convierte en una instancia de la clase alumno.
Cuando se instancia un objeto, se crea un objeto moldeado con base en una clase
específica. Es decir, la clase es el molde (o plantilla) y el objeto es lo que sale de él.
Vale la pena redundar en este enunciado, la clase es la que indica el estado y el
comportamiento válidos para los objetos que se instanciarán a partir de ella.
--- 8 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
3.5. Abstracción
Las clases que conformarán la solución del problema que queremos resolver,
mediante el desarrollo de software orientado a objetos, deben ajustarse a ciertos
principios que permitan desarrollar clases bien diseñadas, que a final de cuentas
nos garanticen todos los beneficios de la POO.
Considera ahora que observas un paisaje. Desde el punto de vista de un artista, este
quizás admire los colores y la textura de los árboles. Si fuera un arquitecto, quizás solo
observe el mejor lugar para la construcción de alguna vivienda. Si fuera un ecologista,
quizás solo le interesen las distintas especies de árboles o plantas o animales que ahí
existen. Mientras tanto, si es un niño el que ve el paisaje, quizás solo le interese el árbol
en que se podrá subir. Como podemos observar, para cada
--- 9 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
uno de estos observadores hay elementos comunes, como los árboles, pero para
cada abstracción conceptual hay elementos que solo son importantes desde el
punto de vista de cada observador.
La abstracción nos permite definir una interfaz para interactuar con los objetos que
se encuentran fuera de nuestro sistema. Además, nos permite definir un sistema
flexible que tenga la posibilidad de extenderse en formas que, inclusive al momento
de diseñarlo, todavía desconozcamos.5
3.6. Encapsulación
--- 10 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
Otro de los principios que deben regir el diseño de las clases, es la encapsulación.
El término encapsulación, dentro de la POO, representa aquella propiedad que
tienen los objetos de no permitir que sus atributos y métodos sean accesibles de
manera externa.21 Esta propiedad es muy adecuada cuando se realizan programas
grandes, ya que se pueden desarrollar módulos de manera independiente y,
posteriormente, incluirlos en el proyecto global. Un ejemplo básico de este concepto
es el estéreo de un carro, para el conductor el auto le permite seleccionar una
estación de radio o reproducir música por algún medio, sin embargo, se le oculta el
cómo trabaja el reproductor, pues los componentes del estéreo están ocultos tanto
a la vista del conductor como a su manipulación. En este sentido, el
encapsulamiento consiste en un proceso mediante el cual se oculta la información
y solo se presenta al usuario una interfaz pública (los métodos públicos) para que
pueda interactuar con el objeto (ver Figura 1).
Objeto A Objeto B
Atributos Atributos
Acceso Acceso
Mensajes
Métodos Métodos
Objeto C
Mensajes Mensajes
Atributos
Acceso
Métodos
----
Figura 1. Encapsulación y paso de mensajes
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
que otro objeto C representa a un curso C. Dado que los objetos se comunican entre sí
a través de mensajes, el objeto A le manda un mensaje X al objeto C solicitando los
cursos a los que se puede inscribir. Como respuesta, el objeto C le manda un mensaje
Y al objeto A indicándole qué tipos de cursos están libres. Tanto al objeto A como al
objeto C no les interesa saber cómo está implementado el software que les permite
llevar a cabo sus funciones. Ahora bien, si alguien modifica el objeto C para mejorar el
tiempo de respuesta, mediante el encapsulamiento el objeto A no sabrá si se ha
modificado o no el comportamiento del objeto C, pues solo estará esperando la
respuesta de a qué curso se puede inscribir. De esta manera los objetos funcionarán
Cuando se trabaja con un objeto de una clase en el que tanto sus datos como sus
métodos están encapsulados, el usuario del objeto solo dispone de una interfaz
pública,23 mediante la cual puede conocer los servicios que puede solicitar al objeto
3.6.1. Visibilidad
iii Cuando se crea una clase se crea un tipo de datos nuevo, este tipo debe exponer solo lo que es
necesario a los clientes a los que les proporcionará algún servicio y mantener oculto todo lo demás.
Dicho control de acceso le permite al diseñador cambiar los detalles internos de implementación de
la clase, sin preocuparse de que, con esto, pueda afectar a los clientes de la misma (ocultamiento
de información).5
--- 12 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
--- 13 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
El aspecto básico de la POO es definir clases, de tal manera que los objetos que
son instancias de estas clases puedan comunicarse entre sí, a través de la interfaz
pública definida por la clase, mediante el envío y recepción de mensajes. Cuando
se lleva a cabo el desarrollo de un programa orientado a objetos, este estará
conformado de varios objetos entre los cuales el mensaje será el único medio de
comunicación, como se ilustra en la Figura 1.
--- 14 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
lista.añadirNombreAlumno(nombreAlumno)
--- 15 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
El UML fue desarrollado principalmente por Grady Booch, Ivar Jacobson y James
Rumbaugh, como una evolución del trabajo que cada uno había desarrollado
individualmente hasta el momento. Al día de hoy, el desarrollo del UML está
controlado por el Grupo de administración de objetos (OMG – Object Management
Group), aunque existen variantes y extensiones no oficiales.
El UML versión 2.0 fue aprobado por el OMG en 2003 y liberado en 2004. Aunque
la mayoría de los cambios se encuentran tras bambalinas para el usuario inexperto,
esta versión expande la notación y los modelos de la versión anterior, mejora el
soporte del uso del UML en la generación automática de código y añade el soporte
para la arquitectura manejada por modelos (model driven architecture).
El diagrama de casos de uso presenta el modelo inicial del sistema, mostrando una
representación gráfica de los servicios que el sistema proporcionará. Se utiliza
durante la fase de inicio del proyecto y ayuda a establecer los límites de este. Por
el momento no ahondaremos más en este tipo de diagrama.
Los modelos estáticos presentan una instantánea del sistema en un punto específico
en el tiempo, mostrando la estructura del mismo. Estos modelos son: los diagramas de
clases, de objetos, de paquetes, de componentes y de despliegue (deployment).
--- 16 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
Los diagramas de clase muestran las relaciones entre las clases que componen el
sistema, siendo el modelo más común. Estos diagramas se pueden mostrar en
niveles de abstracción diferentes, esto es, se puede omitir una gran cantidad de
detalles en favor de la claridad de lo que se desea transmitir con el diagrama.
--- 17 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
--- 18 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
Cuando los objetos interactúan entre sí, generan relaciones entre ellos. Un sistema
orientado a objetos está definido por los objetos que lo conforman y las relaciones
que existen entre ellos.6 A continuación veremos las formas principales de relación
entre clases y entre objetos que son instancias de esas clases.
--- 19 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
factible etiquetar con roles o papeles cada extremo de la relación (ver Figura 5).
--- 20 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
Para que un atributo se considere como parte de una relación de agregación, debe ser
un objeto instancia de una clase. La mayoría de los lenguajes de programación cuentan
con datos de tipo básico o fundamental (por ejemplo los tipos int, float y double
de C++), los cuales no generan una relación de agregación entre dos clases.
--- 21 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
--- 22 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
vii El nombre de cualquier clase debe ser indicado en singular, la multiplicidad indicará el número de
objetos involucrados en cada situación.
--- 23 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
Usualmente al emplear herencia tendremos más de una clase derivada. Por ejemplo,
la Figura 8 muestra la forma de representar en el UML la relación de herencia y cómo
heredan de la clase base Figura, las clases Círculo, Cuadrado y
Triángulo. Esto es, un objeto de la clase Círculo es un objeto de la clase
Figura; un objeto de la clase Cuadrado es una Figura; y, un Triángulo, es
una Figura. Debemos observar que la flecha en la relación de herencia apunta
hacia la clase más general, es decir, indica el sentido de la relación de
generalización.
La clase base contiene todas las características y comportamientos que las clases
derivadas comparten. Con la herencia, las clases derivadas definen un nuevo tipo
de objetos, los cuales contienen todos los atributos de la clase base más su interfaz
pública (todos los métodos públicos de la clase base).
Un detalle en el que cabe la pena redundar, los objetos que son instancias de las
clases derivadas también son del tipo de la clase base. Es decir, en la Figura 8, un
--- 24 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
--- 25 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
Las clases abstractas así como los métodos abstractos, se representan en el UML como
Figura 9. Diagrama de clases de herencia, con una clase y tres métodos abstractos.
--- 26 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
Resumiendo lo visto en este apartado tenemos que existen dos tipos de herencia:
la herencia completa y la herencia de interfase;5 y tenemos que existen dos tipos
de procedimientos para la reutilización de código por medio de la herencia: la
especialización y la generalización.27 Además, es importante mencionar que no se
pueden instanciar (crear) objetos de una clase abstracta, esto solo se puede realizar
de clases concretas, es decir, de aquellas clases que cuentan con la
implementación de todos los métodos declarados por su clase base (aunque sea
abstracta) y por ella misma.
clase Figura. La herencia de interfaz es cuando las clases derivadas reciben solamente
la declaración de los métodos de la clase base, es decir, que tales métodos son abstractos
(y, por lo tanto, también lo es la clase base).
En la Figura 9, las clases derivadas reciben la herencia de interfaz de los métodos
--- 27 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
Uno de los preceptos que mejor resumen las situaciones bajo las cuales es conveniente
utilizar la herencia es el principio de substitución de Liskov (LSP):28 “Es aceptable
derivar la clase B de la clase A solamente si, para cada método en las interfaz públicas
de A y B, los métodos de B aceptan como entrada todos los valores que los métodos
de A aceptan (y posiblemente más) y, a la par, realizan sobre esos valores todo lo que
los métodos de A realizan sobre ellos (y posiblemente más)”.
La clase Rectángulo debe contar con un método que modifique sus medidas,
--- 28 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
3.9.5. Polimorfismo
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
if (tipoEmpleado == GERENTE)
{
salario = 50000.0;
}
else if (tipoEmpleado == SUBGERENTE)
{
salario = 40000.0;
}
else if (tipoEmpleado == JEFE_DE_PROYECTO)
{
salario = 30000.0;
}
--- 30 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
return salario;
} // calcularSalario()
double calcularISR()
{
double isr = 0.0;
if (tipoEmpleado == GERENTE)
{
isr = 5000.0;
}
else if (tipoEmpleado == SUBGERENTE)
{
isr = 4000.0;
}
else if (tipoEmpleado == JEFE_DE_PROYECTO)
{
isr = 3000.0;
}
else if (tipoEmpleado == JEFE_DE_DEPARTAMENTO)
{
isr = 2000.0;
}
else // tipoEmpleado == EMPLEADO_NORMAL
{
isr = 1500.0;
}
--- 31 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
return isr;
} // calcularISR()
double calcularIVA()
{
double iva = 0.0;
if (tipoEmpleado == GERENTE)
{
iva = 500.0;
}
else if (tipoEmpleado == SUBGERENTE)
{
iva = 400.0;
}
else if (tipoEmpleado == JEFE_DE_PROYECTO)
{
iva = 300.0;
}
else if (tipoEmpleado == JEFE_DE_DEPARTAMENTO)
{
iva = 200.0;
}
else // tipoEmpleado == EMPLEADO_NORMAL
{
iva = 175.0;
}
return iva;
} // calcularIVA()
double calcularSAR()
{
--- 32 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
if (tipoEmpleado == GERENTE)
{
sar = 2500.0;
}
else if (tipoEmpleado == SUBGERENTE)
{
sar = 2400.0;
}
else if (tipoEmpleado == JEFE_DE_PROYECTO)
{
sar = 2300.0;
}
else if (tipoEmpleado == JEFE_DE_DEPARTAMENTO)
{
sar = 2200.0;
}
else // tipoEmpleado == EMPLEADO_NORMAL
{
sar = 1500.0;
}
return sar;
} // calcularSAR()
Ahora bien, ¿qué cambios debemos realizar a los cálculos si se añade el tipo de
empleado EMPLEADO_DE_CONFIANZA?
La respuesta es que, en cada una de las funciones que realizan los cálculos,
debemos agregar una cláusula if (tipoEmpleado == EMPLEADO_DE_CONFIANZA)
colocando, además, las instrucciones necesarias para asignar a las variables
salario, isr, iva y sar el monto apropiado para este tipo de empleado.
--- 33 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
--- 34 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
} // Gerente::calcularSalario()
double Gerente::calcularISR()
{
return 5000.0;
} // Gerente::calcularISR()
double Gerente::calcularIVA()
{
return 500.0;
} // Gerente::calcularIVA()
--- 35 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
double Gerente::calcularSAR()
{
return 2500.0;
} // Gerente::calcularSAR()
double Subgerente::calcularSalario()
{
return 40000.0;
} // Subgerente::calcularSalario()
double Subgerente::calcularISR()
{
return 4000.0;
} // Subgerente::calcularISR()
double Subgerente::calcularIVA()
{
return 400.0;
} // Subgerente::calcularIVA()
double Subgerente::calcularSAR()
{
return 2400.0;
} // Subgerente::calcularSAR()
double JefeProyecto::calcularSalario()
{
return 30000.0;
--- 36 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
} // JefeProyecto::calcularSalario()
double JefeProyecto::calcularISR()
{
return 3000.0;
} // JefeProyecto::calcularISR()
double JefeProyecto::calcularIVA()
{
return 300.0;
} // JefeProyecto::calcularIVA()
double JefeProyecto::calcularSAR()
{
return 2300.0;
} // JefeProyecto::calcularSAR()
double JefeDepartamento::calcularSalario()
{
return 20000.0;
} // JefeDepartamento::calcularSalario()
double JefeDepartamento::calcularISR()
{
return 2000.0;
} // JefeDepartamento::calcularISR()
--- 37 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
double JefeDepartamento::calcularIVA()
{
return 200.0;
} // JefeDepartamento::calcularIVA()
double JefeDepartamento::calcularSAR()
{
return 2200.0;
} // JefeDepartamento::calcularSAR()
double EmpleadoNormal::calcularSalario()
{
return 10000.0;
} // EmpleadoNormal::calcularSalario()
double EmpleadoNormal::calcularISR()
{
return 1500.0;
} // EmpleadoNormal::calcularISR()
double EmpleadoNormal::calcularIVA()
{
return 175.0;
} // EmpleadoNormal::calcularIVA()
double EmpleadoNormal::calcularSAR()
{
--- 38 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
return 1500.0;
} // EmpleadoNormal::calcularSAR()
Lo único que debemos considerar para obtener todas las ventajas del polimorfismo,
cuando tratamos con jerarquías de tipos, es tratar a los objetos como si fueran del
tipo de su clase base, no de su tipo real.
--- 39 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
--- 40 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
Referencias
http://es.wikipedia.org/wiki/Paradigma
3 Intel Corporation. “Moore’s Law and Intel Innovation.” Consultado: 29 de noviembre de 2013, de
http://www.intel.com/content/www/us/en/history/museum-gordon-moore-law.html
4 C. Harrison, J. “Do You Suffer from Paradigm Paralysis?” Consultado: 29 de noviembre de 2013,
de http://www.mnsu.edu/comdis/kuster/Infostuttering/Paradigmparalysis.html
5 Amdocs. “Object Oriented Concepts.” Consultado: 29 de noviembre de 2013, de
http://pro-cess.co.il/downloads/Dreams_come_true.ppt
6 Matincor, Inc. “An Introduction to Object-Oriented Analysis and Design using UML.” Consultado:
29 de noviembre de 2013, de http://www.matincor.com/Documents/Intro_OOAD.pdf
7 Real Academia Española. “Diccionario de la lengua española”. Consultado: 29 de noviembre de
2013, de http://lema.rae.es/drae/?val=objeto
8 Booch, G. (1998) Análisis y diseño orientado a objetos con aplicaciones, 2ª Ed. Naucalpan de
Juárez, Estado de México: Addison Wesley Longman de México, S. A. de C. V.
9 Deitel, P. & Deitel, H. (2014) C++ How to Program, 9th. Ed. Boston, Massachusetts: Pearson
Education, Inc.
10 S. Horstmann, C. (2006) Object-Oriented Design & Patterns, 2nd. Ed. Hoboken, New Jersey: John
Wiley & Sons, Inc.
11S. Horstmann, C. & A. Budd, T. (2009) Big C++, 2nd. Ed. New Jersey: John Wiley & Sons, Inc.
12Savitch, W. (2013) Absolute C++, 5th. Ed. Boston, Massachusetts: Pearson Education, Inc.
13 S. Malik, D. (2012) C++ Programming: Program Design Including Data Structures, 6th. Ed. Boston,
Massachusetts: Cengage Learning.
14 Liberty, J. & Jones, B. (2005) Teach Yourself C++ in 21 Days, 5th. Ed. Indianapolis, Indiana, USA:
Sams Publishing.
15 J. Bronson, G. (2007) C++ para ingeniería y ciencias, 2ª Ed. México, D. F.: Cengage Learning
Editores, S. A. de C. V.
16 Kimmel, P. (2007) Manual de UML. México, D. F.: McGraw-Hill Interamericana Editores, S. A. de
C. V.
--- 41 ----
CONALEP MICHOACÁN
2014 [INTRODUCCIÓN A LA POO]
17 Barker, J. (2005) Beginning Java Objects: From concepts to code, 2nd. Ed. California, USA: Apress
Media LLC.
18 Booch, G. & Cueva L., J. M. & Cernuda del R., A. (1996) Análisis y diseño orientado a objetos con
aplicaciones. Naucalpan de Juárez, Estado de México: Addison Wesley Longman de México, S. A.
de C. V.
19 Cobo Y., Á. (2000) Programar desde un punto de vista científico. Madrid, España: Editorial Visión
Libros.
20 José P., M. (2004) C y C++ de afán, 2ª Ed. Antioquía, Colombia: Editorial Universidad de Antioquía.
21 Martínez G., F. & Martoin Q., G. (2003) Introducción a la programación estructurada en C.
Valencia, España: Universidad de Valencia.
22 Ramírez J., F. (2007) Aprenda Visual Basic 2005 con Visual Studio 2005. México, D. F.: Pearson
Education.
23S. Horstmann, C. (2012) Big Java, Late Objects. New Jersey: John Wiley & Sons, Inc.
24 H. Saltzer, J. (1974) Protection and the control of information sharing in multics. Communications
of the ACM, Volume 17, Issue 7, July 1974, Pages 388-402. Consulta 29 de noviembre de 2013, de
http://dx.doi.org/10.1145/361011.361067
25 Rumbaugh, J. & Jacobson, I. & Booch, G. (2005) The Unified Modeling Language Reference
Manual, 2nd. Ed. Boston, Massachusetts: Pearson Education, Inc.
26 Kimmel, P. (2007) Manual de UML. México, D. F.: McGraw-Hill Interamericana Editores, S. A. de
C. V.
27 Skrien, D. (2009) Object-Oriented Design Using Java. New York, New York: The McGraw-Hill
Companies, Inc.
28 Liskov, B. “Liskov Substitution Principle.” Consultado: 29 de noviembre de 2013, de
http://c2.com/cgi/wiki?LiskovSubstitutionPrinciple
--- 42 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 1 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
Cada uno de los ejemplos previos que hemos construido maneja un solo archivo de
código fuente con extensión “.cpp”. Cuando se desarrolla software en un ambiente
profesional, es habitual que coloquemos el código fuente reutilizable (como los
prototipos de las funciones y, como veremos más adelante, las declaraciones de
clases) en un archivo que, por convención, tiene extensión “.h”. A estos archivos
se les denomina archivos de cabecera (headers) y nos ayudan a organizar el código
fuente, de tal manera que es más fácil de entender.
--- 2 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
Como podemos observar, el Listado 9 consiste de prácticamente las líneas iniciales del
Listado 2, solo se diferencian en el código de las líneas 5, 6 y 23. Estas líneas:
#ifndef ESTADISTICAS_H
#define ESTADISTICAS_H
.
.
.
#endif // ESTADISTICAS_H
--- 3 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
6. // Definición de constantes
7. const unsigned int MAX_DATOS = 25;
8.
9.
10. int main(void)
11. {
12. int *datos = new int[MAX_DATOS]();
13. int numDatos = solicitarDatos(datos);
14.
15. if (numDatos > 0)
16. {
17. ordenarDatos(datos, numDatos);
18.
19. double media = calcularMedia(datos, numDatos);
20. double mediana = calcularMediana(datos, numDatos);
21. int moda = calcularModa(datos, numDatos);
22.
23. imprimirDatos(datos, numDatos);
24. cout << "\nLa media es: " << setprecision(2) << fixed <<
media
25. << "\nLa mediana es: " << mediana 26. << "\nLa
moda es: " << moda << endl;
29. }
30. else
31. {
32. cout << "\nNo se introdujeron datos." << endl;
33. }
32.
33. // Devolver la memoria dinámica y asignar un valor
34. // seguro al apuntador
35. delete [] datos;
36. datos = NULL;
37.
38. return 0;
39.
40. } // main()
41.
42.
43. // Solicita y lee datos enteros en el rango [0 - 10]. Un número negativo
44. // finaliza la entrada de datos.
45. // datos: Arreglo donde se recibirán los elementos solicitados.
46. // Devuelve el número de datos leído.
47. int solicitarDatos(int datos[])
48. {
49. int numDatos = 0;
50. int unDato = leerDato();
51.
52. while (unDato >= 0)
53. {
54. datos[numDatos] = unDato;
55. ++numDatos;
56.
57. unDato = leerDato();
58.
59. } // while
--- 4 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
60.
61. return numDatos;
62.
63. } // solicitarDatos()
64.
65.
66. // Lee un dato de tipo entero <= 10. Un número negativo
67. // finaliza la entrada de datos.
68. // Devuelve el dato leído.
69. int leerDato(void)
70. {
71. int unDato = 0;
72.
73. do
74. {
75. cout << "\nTeclee un entero (-1 para terminar):
76. cin >> unDato; , 0 ≤ x ≤ 10 ";
77.
78. } while (unDato > 10);
79.
80. return unDato;
81.
82. } // leerDato()
83.
84.
85. // Ordena los 'numDatos' primeros elementos de un arreglo
86. // datos: Arreglo a ordenar
87. // numDatos: Número de elementos a ordenar del arreglo
88. void ordenarDatos(int datos[], int numDatos)
89. {
90. for (int i = 0; i < (numDatos - 1); ++i)
91. {
92. int minj = i;
93.
94. for (int j = i + 1; j < numDatos; ++j)
95. {
96. if (datos[j] < datos[minj])
97. {
98. minj = j;
99. }
100.
101. } // for j
102.
103. intercambiar(datos[i], datos[minj]);
104.
105. } // for i
106.
107. } // ordenarDatos()
108.
109.
110. // Intercambia el valor de dos variables
111. // n1: Primera variable a intercambiar
112. // n2: Segunda variable a intercambiar
113. void intercambiar(int& n1, int& n2)
114. {
115. int temp = n1;
--- 5 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
116. n1 = n2;
117. n2 = temp;
118.
119. } // intercambiar()
120.
121.
122. // Calcula la media de los primeros 'numDatos' elementos de un
arreglo
123. // datos: Arreglo de elementos cuya media se va a calcular
124. // numDatos: Número de elementos del arreglo cuya media se calculará
125. double calcularMedia(int datos[], int numDatos)
126. {
127. double suma = 0.0;
128.
129. for (int i = 0; i < numDatos; ++i)
130. {
131. suma += datos[i];
132.
133. } // for i
134.
135. return (suma / numDatos);
136.
137. } // calcularMedia()
138.
139.
140. // Calcula la mediana de los elementos de un arreglo
141. // datos: Arreglo de elementos cuya mediana se va a calcular
142. // numDatos: Número de elementos del arreglo cuya mediana se calculará
143. double calcularMediana(int datos[], int numDatos)
144. {
145. double mediana = 0.0;
146. int indiceMediana = numDatos / 2;
147.
148. if ((numDatos % 2) == 1) // El número de datos es impar
149. {
150. mediana = datos[indiceMediana];
151. }
152. else // El número de datos es par
153. {
154. double suma = static_cast<double>(datos[indiceMediana - 1] +
155. datos[indiceMediana]);
156. mediana = suma / 2;
157. }
158.
159. return mediana;
160.
161. } // calcularMediana()
162.
163.
164. // Calcula la moda de los primeros 'numDatos' elementos de un arreglo
165. // datos: Arreglo de elementos cuya moda se va a calcular
166. // numDatos: Número de elementos del arreglo cuya moda se va a calcular
167. int calcularModa(int datos[], int numDatos)
--- 6 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
168. {
169. int frecuencias[11] = {0};
170.
171. // Contar las ocurrencias de cada valor
172. for (int i = 0; i < numDatos; ++i)
173. {
174. ++frecuencias[ datos[i] ];
175.
176. } // for i
177.
178. int iMaximo = 0;
179.
180. // Buscar la moda
181. for (int i = iMaximo + 1; i < 11; ++i)
182. {
183. if (frecuencias[iMaximo] < frecuencias[i])
184. {
185. iMaximo = i;
186. }
187.
188. } // for i
189.
190. return iMaximo;
191.
192. } // calcularModa()
193.
194.
195. // Imprime en pantalla los primeros 'numDatos' elementos de un
arreglo
196. // datos: Arreglo a imprimir
197. // numDatos: Número de elementos a imprimir del arreglo
198. void imprimirDatos(int datos[], int numDatos)
199. {
200. cout << "\nDatos = [";
201.
202. for (int i = 0; i < numDatos; ++i)
203. {
204. cout << " " << datos[i];
205.
206. } // for i
207.
208. cout << " ]" << endl;
209.
210. } // imprimirDatos()
--- 7 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
asigna el espacio de memoria suficiente para almacenar una variable de tipo entero, la
--- 8 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 9 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
El resto del código en el Listado 10 permanece sin cambios por lo que, la salida en
pantalla de una ejecución de prueba del programa del Listado 10, es como podía
esperarse:
Teclee un entero x, 0 <= x <= 10 (-1 para terminar): 3
Teclee un entero x, 0 <= x <= 10 (-1 para terminar): 4
Teclee un entero x, 0 <= x <= 10 (-1 para terminar): 2
Teclee un entero x, 0 <= x <= 10 (-1 para terminar): 3
Teclee un entero x, 0 <= x <= 10 (-1 para terminar): 2
Teclee un entero x, 0 <= x <= 10 (-1 para terminar): 1
Teclee un entero x, 0 <= x <= 10 (-1 para terminar): 1
Teclee un entero x, 0 <= x <= 10 (-1 para terminar): 2
Teclee un entero x, 0 <= x <= 10 (-1 para terminar): 1
Teclee un entero x, 0 <= x <= 10 (-1 para terminar): 1
Teclee un entero x, 0 <= x <= 10 (-1 para terminar): 2
Teclee un entero x, 0 <= x <= 10 (-1 para terminar): 1
Teclee un entero x, 0 <= x <= 10 (-1 para terminar): 1
Teclee un entero x, 0 <= x <= 10 (-1 para terminar): -1
Datos = [ 1 1 1 1 1 1 2 2 2 2 3 3 4 ]
--- 10 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
+ ×, = −1
--- 11 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
9. public:
10. Complejo();
11. Complejo(double real, double imaginaria);
12. ~Complejo() {}
13. double obtenerParteReal() { return parteReal; }
14. void establecerParteReal(double real) { parteReal = real; }
15. double obtenerParteImaginaria() { return parteImaginaria; }
16. void establecerParteImaginaria(double imaginaria) {
17. parteImaginaria = imaginaria;
18. }
19. Complejo *mas(Complejo *unComplejo);
20. Complejo *menos(Complejo *unComplejo);
21. Complejo *por(Complejo *unComplejo);
22. Complejo *por(double escalar);
23. Complejo *entre(Complejo *unComplejo);
24. Complejo *entre(double escalar);
25. void imprimir(void);
26. protected:
27. private:
28. double parteReal;
29. double parteImaginaria;
30.
31. };
32.
33. #endif // COMPLEJO_H
Primeramente observamos que este archivo de cabecera también cuenta con los
guardias de inclusión vistos anteriormente, en las líneas 3, 4 y 33 del Listado 11.
Luego podemos observar que C++ define una clase con la palabra reservada class
y el nombre de la clase. Es una convención habitual el colocar el nombre de la clase
iniciando con una letra mayúscula y el resto del nombre en notación camello, es
decir, todas las letras en minúsculas excepto la primera letra de cada palabra,
cuando el nombre de la clase se conforma de varias palabras, que debe ir en
mayúsculas. Ejemplos: VehículoTodoTerreno, ImpresoraLáserColor,
DepartamentoDeVentas, etc.
--- 12 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
Observemos una cuestión importante en el Listado 11, tenemos funciones miembro que
no cuentan con el cuerpo de su definición, es decir, terminan en “;”. Además, tenemos
cinco funciones (contando al destructor, explicado en el apartado siguiente, que tiene
un cuerpo vacío) que sí cuentan con su definición completa.
El punto anterior tiene dos motivos de ser: el primero consiste en que solo las
funciones miembro que cuentan con una definición muy pequeña se acostumbran
colocar en el archivo de cabecera; el segundo motivo se basa en la encapsulación
de la información y en el principio del privilegio mínimo, es decir, las clases cliente
(y los programadores que las desarrollan) no necesitan ni deberían tener acceso a
la implementación de nuestra clase, solamente a la interfaz pública, así, si más
adelante podemos optimizar el desempeño de nuestra clase, estaremos en
posibilidades de cambiar la forma en que está implementada, sin preocuparnos de
afectar a las clases clientes que la utilizan. Por esta razón, la implementación real
de las funciones se realiza en un archivo “.cpp” aparte, para ocultar la
implementación.
--- 13 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
Siguiendo con el análisis del Listado 11, las líneas 10 a 25 presentan las funciones
miembro de la clase Complejo, todas las cuales son de acceso público, como ya
dijimos. En el diagrama de clases del UML mostrado en la Figura 1, se utilizó el
estereotipo «constructor» para resaltar dos funciones miembro (sobrecargadas)
con el mismo nombre de la clase y sin valor de devolución de la función. Estas
funciones miembros se denominan constructores.
inicialicen apropiadamente.1, 2
Volviendo al diagrama del UML de la Figura 1, la otra función miembro que está
marcada con un estereotipo, es el destructor. Un destructor es una función miembro
especial de una clase que se utiliza para realizar labores de limpieza antes de que el
--- 14 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
objeto del que forma parte sea destruido. Por ejemplo, si el constructor de la clase
asigna espacio dinámicamente para uno o varios objetos que la clase agregue o de
la que esté compuesta (o para un arreglo de ellos), el destructor puede emplearse
para liberar dicho espacio de memoria, devolviéndolo al sistema operativo. El
nombre del destructor para una clase consiste del carácter tilde “~” seguido por el
nombre de la clase.
Al igual que sucede con los constructores, todas las clases tienen un destructor. Si
no proporcionamos el destructor explícitamente, C++ proporcionará un destructor
implícito vacío (sin instrucciones en el cuerpo de su definición).
Para terminar el tema sobre destructores hay que señalar que no se pueden pasar
argumentos a un destructor, que no es posible especificarle un tipo de valor de
devolución, que no se puede devolver un valor cuando el destructor termina y que
tampoco se puede sobrecargar. Si algo de lo anterior se intenta, el resultado será la
generación de un mensaje de error por parte del compilador.
--- 15 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
El objetivo es que todo el acceso a las variables internas de la clase se realice a través
de las dos funciones mencionadas,iii así, cualquier problema que surja con relación a la
integridad de las variables será fácil de depurar, ya que el problema se encontrará
seguramente en una de dichas funciones. Resulta lógico pensar, por supuesto, que
dentro de estas funciones el acceso a las variables miembro es directo.
Cabe señalar que las funciones establecer (set) tienen otro propósito muy
importante, el de validar los valores con los cuales se intentan inicializar las
variables miembro. Por ejemplo, si la clase Persona maneja la variable miembro
edad, la función miembro establecerEdad() puede y debe validar que esta no
sea un número negativo; en tal caso, debe arrojar un mensaje de error y rechazar
la modificación, pudiendo asignar un valor predeterminado a la variable citada a fin
de dejar en un estado consistente el objeto que se está manipulando.
iii En ocasiones, por cuestiones de rendimiento, se sugiere realizar el acceso directo a las variables
miembro de la clase. También existe quien sugiere que el acceso a estas variables desde los
constructores debe realizarse directamente, ya que el objeto en cuestión todavía no cuenta con un
estado inicial, es decir, el objeto debe construirse completamente antes de utilizarse.
--- 16 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
9. Complejo::Complejo()
10. : parteReal(0.0), parteImaginaria(0.0)
11. {
12. }
13.
14.
15. Complejo::Complejo(double real, double imaginaria)
16. : parteReal(real), parteImaginaria(imaginaria)
17. {
18. }
19.
20.
21. Complejo *Complejo::mas(Complejo *unComplejo)
22. {
23. return new Complejo(
24. obtenerParteReal() + unComplejo->obtenerParteReal(),
25. obtenerParteImaginaria() +
26. unComplejo->obtenerParteImaginaria()
27. );
28.
29. }
30.
31.
32. Complejo *Complejo::menos(Complejo *unComplejo)
33. {
34. return new Complejo(
35. obtenerParteReal() - unComplejo->obtenerParteReal(),
36. obtenerParteImaginaria() –
37. unComplejo->obtenerParteImaginaria()
38. );
39.
40. }
41.
42.
43. Complejo *Complejo::por(Complejo *unComplejo)
44. {
45. double a = obtenerParteReal();
46. double b = obtenerParteImaginaria();
47. double c = unComplejo->obtenerParteReal();
48. double d = unComplejo->obtenerParteImaginaria();
49.
50. return new Complejo(
51. (a * c) - (b * d),
52. (a * d) + (b * c)
53. );
54.
55. }
56.
57.
58. Complejo *Complejo::por(double escalar)
59. {
60. return new Complejo(
61. escalar * obtenerParteReal(),
62. escalar * obtenerParteImaginaria()
63. );
64.
--- 17 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
65. }
66.
67.
68. Complejo *Complejo::entre(Complejo *unComplejo)
69. {
70. double a = obtenerParteReal();
71. double b = obtenerParteImaginaria();
72. double c = unComplejo->obtenerParteReal();
73. double d = unComplejo->obtenerParteImaginaria();
74.
75. return new Complejo(
76. ((a * c) + (b * d)) / ((c * c) + (d * d)),
77. ((b * c) - (a * d)) / ((c * c) + (d * d))
78. );
79.
80. }
81.
82.
83. Complejo *Complejo::entre(double escalar)
84. {
85. return new Complejo(
86. obtenerParteReal() / escalar,
87. obtenerParteImaginaria() / escalar
88. );
89.
90. }
91.
92.
93. void Complejo::imprimir(void)
94. {
95. cout << "(" << obtenerParteReal() << ", "
96. << obtenerParteImaginaria() << ")";
97.
98. }
En las líneas 3 y 4 del Listado 12 podemos ver la inclusión de los archivos de cabecera
de la biblioteca estándar así como de nuestra clase Complejo. Luego declaramos el
empleo del espacio de nombres estándar, en la línea 6. Más adelante, en las líneas 9,
15, 21, 32, 43, 58, 68, 83 y 93 usamos el operador de resolución de
--- 18 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
ámbito “::” para señalar que las funciones miembro cuyas cabeceras se encuentran
en cada una de esas líneas pertenecen a la clase Complejo. Las definiciones de estas
miembro parteReal debe inicializarse con el valor 0.0 y que, la variable miembro
Por su parte:
Complejo::Complejo(double real, double imaginaria)
: parteReal(real), parteImaginaria(imaginaria)
--- 19 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
imaginaria.
Observemos que los cuerpos de los constructores están vacíos, ya que los valores
de las variables internas ya fueron establecidos con las listas de inicialización.
c = a->mas(b);
Luego entonces, lo que la función mas() realiza en las líneas 23 a 27 del Listado 12,
es simplemente instanciar un objeto nuevo de tipo Complejo, pasándole al constructor
que recibe dos parámetros la suma de las partes reales del objeto actual (el que está
ejecutando su función mas() –el objeto al que apunta la variable a, en el ejemplo escrito
párrafos arriba) y el objeto al que apunta la variable recibida como
--- 20 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
Debemos precisar un detalle del código que implementa la función mas() (y de todas
las demás funciones miembro de la clase Complejo). Cuando queremos accesar uno
de los miembros (variable o función) del objeto actual, simplemente colocamos el
nombre de la variable (como en las líneas 13, 14, 15 y 17 del archivo de cabecera en
el Listado 11) o el de la función correspondiente (como en las líneas 24, 25, 35, 36, 45,
46, 61, 62, 70, 71, 86, 87, 95 y 96 del Listado 12). En cambio, cuando las variables o
las funciones miembro que queremos accesar son las del objeto referenciado por una
variable apuntador (como el argumento unComplejo recibido en las funciones
miembro de la clase Complejo), debemos usar el nombre de la variable apuntador, el
operador flecha y el nombre de la variable o función miembro (como en las líneas 24,
26, 35, 37, 47, 48, 72 y 73 del Listado 12).
Las otras funciones miembro de la clase Complejo realizan la misma tarea que la
función mas() antes descrita, con la salvedad de que aplican una operación
diferente (la resta, la multiplicación, la multiplicación por un escalar, la división y la
división entre un escalar). La última función miembro, la función imprimir(),
simplemente presenta el número complejo en pantalla en el formato
(parte_real, parte_imaginaria).
Finalmente, como la clase solo define un tipo de datos nuevo (con estado y
comportamiento, eso sí), esto es equivalente a saber que existe un tipo de datos
--- 21 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 22 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
48. return 0;
49.
50. }
En las líneas 10 a 13, del Listado 13, definimos cuatro variables apuntador a objetos
de la clase Complejo. Tres de ellos los inicializamos al mismo tiempo que el
operador new asigna memoria dinámica para ellos. Recordemos, otra vez, que el
operador new llama al constructor de la clase cuyo número de parámetros coincida
con el número de parámetros entre los paréntesis de esta instrucción.
Posteriormente, en las líneas 15 a 21, imprimimos en pantalla los tres números
complejos inicializados.
Más adelante, líneas 23 a 26 del Listado 13, asignamos la suma de dos de los
números complejos inicializados al número complejo sin inicializar, y el resultado lo
imprimimos en pantalla. Esto mismo lo repetimos en las líneas 28 a 31, para la resta;
en las líneas 33 a 36, para la multiplicación; en las líneas 38 a 41, para la división;
y, en las líneas 43 a 46, para mostrar otro ejemplo de la división. Finalmente,
devolvemos un valor de 0 al sistema operativo, línea 48, indicándole con esto que
el programa terminó su ejecución sin contratiempo.
La suma de a + b, almacenada en c
es: (3, 3)
La resta de d - b, almacenada en c
es: (1, 3)
La multiplicacion de b * d, almacenada en c
--- 23 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
La division de a / b, almacenada en c
es: (0.5, 0)
La division de d / a, almacenada en c
es: (4, 1)
En primer lugar, la Figura 2 presenta el diagrama de clases del UML para la jerarquía
de herencia de las formas geométricas.
Figura 2. Diagrama de clases del UML para la jerarquía de herencia de las formas geométricas
--- 24 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
Observemos que estas tres clases son abstractas, como ya se vio en el capítulo
anterior, por tener al menos una función miembro abstracta.iv En C++, el término
para denominar a una función miembro abstracta es virtual. Además, cuando la
herencia de la función miembro virtual es solamente de interfaz, se denomina virtual
pura.
--- 25 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
v En castellano las palabras círculo y triángulo se acentúan, pero obtamos por eliminar el acento de
ellas en los nombres correspondientes de las clases, a fin evitar problemas sutiles de codificación
de caracteres con el compilador de C++.
--- 26 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 27 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
5.
6. enum Colores {SIN_COLOR, NEGRO, AZUL, CIAN, GRIS_OBSCURO, GRIS,
7. VERDE, GRIS_CLARO, MAGENTA, NARANJA, ROSA, ROJO, BLANCO,
8. AMARILLO};
9.
10. #endif // COLORES_H
--- 28 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
A las variables del tipo definido por el usuario Colores solo se les puede asignar
--- 29 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 30 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
33. private:
34. std::string nombreColor(Colores color);
35.
36. std::string tipo;
37. Colores colorContorno;
38. Colores colorRelleno;
39. };
40.
41. #endif // FORMA_H
Por razones técnicas cuya explicación está más allá del ámbito de este libro, se
recomienda que el constructor (que recibe un solo parámetro) de todas las clases
que desarrollemos, se declare con la opción explicit antes del nombre del
constructor. De la misma manera, se recomienda que en toda clase abstracta o que
forme parte de una jerarquía de herencia de clases en las que exista alguna clase
abstracta, el destructor se declare también como abstracto, es decir, con la palabra
reservada virtual antes del nombre del constructor.
--- 31 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 32 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
57. {
58. case SIN_COLOR:
59. nombre = "Ninguno";
60. break;
61. case NEGRO:
62. nombre = "Negro";
63. break;
64. case AZUL:
65. nombre = "Azul";
66. break;
67. case CIAN:
68. nombre = "Cian";
69. break;
70. case GRIS_OBSCURO:
71. nombre = "Gris obscuro";
72. break;
73. case GRIS:
74. nombre = "Gris";
75. break;
76. case VERDE:
77. nombre = "Verde";
78. break;
79. case GRIS_CLARO:
80. nombre = "Gris claro";
81. break;
82. case MAGENTA:
83. nombre = "Magenta";
84. break;
85. case NARANJA:
86. nombre = "Naranja";
87. break;
88. case ROSA:
89. nombre = "Rosa";
90. break;
91. case ROJO:
92. nombre = "Rojo";
93. break;
94. case BLANCO:
95. nombre = "Blanco";
96. break;
97. case AMARILLO:
98. nombre = "Amarillo";
99. break;
100. default:
101. nombre = "Color inexistente";
102. break;
103. }
104.
105. return nombre;
106. }
--- 33 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 34 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
4.4.4. Herencia
--- 35 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
En la línea 19, también con la palabra reservada virtual, se declara como abstracta
la función miembro imprimir(). Recordemos del Listado 15 en el cual se define la
clase base Forma, que esta función imprimir() se declara como virtual con herencia
de implementación completa, esto es, la clase Forma proporciona una implementación
de dicha función. Lo que nos lleva a que, en la línea 19 del presente Listado 17, la clase
Forma2D está redefiniendo la función miembro imprimir() de la clase Forma, dicho
de otro modo, está substituyendo la función de su clase base
Forma, por su propia función. Esta substitución la hacemos todavía más explícita al
colocar la palabra reservada override,vi al final de la línea 19, la cual es una petición
de ayuda al compilador de C++ para indicarle que queremos redefinir la función y que,
si hay algo que no nos permita realizar dicho proceso, nos lo indique.
--- 36 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 37 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
4.4.4.2. Llamada de funciones miembro de una clase base desde las funciones
miembro de una clase derivada
--- 38 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 39 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
21. }
22.
23.
24. Circulo::Circulo(string unTipo, double unRadio) : Forma2D(unTipo)
25. {
26. establecerRadio(unRadio);
27. }
28.
29.
30. Circulo::~Circulo()
31. {
32. // Cuerpo vacío
33. }
34.
35.
37. void Circulo::establecerRadio(double unRadio)
38. {
39. // Validar el radio
40. if (unRadio >= 0.0)
41. {
42. radio = unRadio;
43. }
44. else
45. {
46. radio = 0.0;
46.
47. }
48.
49. }
50.
51.
52. // Calcula el área del círculo
53. double Circulo::calcularArea()
54. {
55. return PI * obtenerRadio() * obtenerRadio();
56.
57. }
58.
59.
60. // Imprime un objeto de la clase Circulo
61. void Circulo::imprimir()
62. {
63. Forma2D::imprimir();
64.
65. cout << "Radio: " << obtenerRadio() << ", Area: "
66. << calcularArea() << endl;
67.
68. }
--- 40 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
Podemos ver que en la línea 12 de este Listado 20, el constructor utiliza una lista
de inicialización para construir un objeto Circulo pero, además, llama al
constructor de la clase base, Forma2D, para que inicialice la parte del objeto que se
está construyendo y que corresponde a la clase Forma2D. Es importante que esta
llamada al constructor de la clase base se coloque en la primera posición de la lista
de inicialización, el no hacerlo así es un error de sintaxis.
clase_derivada::constructor_clase_derivada() :
constructor_clase_base(parámetros), variable_miembro1(valor1),…
variable_miembroN(valorN){ … }
--- 41 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
sucesivamente, hasta llegar a destruir la parte del objeto que corresponde a la clase
más general.
--- 42 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 43 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
20.
21.
22. Cuadrado::Cuadrado(string unTipo, double unLado) :
23. Forma2D(unTipo)
24. {
25. establecerLado(unLado);
26.
27. }
28.
29.
30. Cuadrado::~Cuadrado()
31. {
32. // Cuerpo vacío
33.
34. }
35.
36.
37. void Cuadrado::establecerLado(double unLado)
38. {
39. // Validar el lado
40. if (unLado >= 0.0)
41. {
42. lado = unLado;
43. }
44. else
45. {
46. lado = 0.0;
47.
48. }
49.
50. }
51.
52.
53. // Calcula el área del cuadrado
54. double Cuadrado::calcularArea()
55. {
56. return obtenerLado() * obtenerLado();
57.
58. }
59.
60.
61. // Imprime un objeto de la clase Cuadrado
62. void Cuadrado::imprimir()
63. {
64. Forma2D::imprimir();
65.
66. cout << "Lado: " << obtenerLado() << ", Area: "
67. << calcularArea() << endl;
68.
69. }
--- 44 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
3. #ifndef TRIANGULO_H
4. #define TRIANGULO_H
5.
6. #include <iostream>
7. #include "forma2d.h"
8.
9.
10. class Triangulo : public Forma2D
11. {
12. public:
13. Triangulo();
14. Triangulo(double unaBase, double unaAltura);
15. Triangulo(std::string unTipo, double unaBase,
16. double unaAltura);
17.
18. virtual ~Triangulo();
19.
20. double obtenerBase() { return base; }
21. void establecerBase(double unaBase);
22.
23. double obtenerAltura() { return altura; }
24. void establecerAltura(double unaAltura);
25.
26. virtual double calcularArea() override;
27. virtual void imprimir() override;
28. protected:
29. private:
30. double base;
31. double altura;
32. };
33.
34. #endif // TRIANGULO_H
--- 45 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
21. }
22.
23.
24. Triangulo::Triangulo(string unTipo, double unaBase,
25. double unaAltura) : Forma2D(unTipo)
26. {
27. establecerBase(unaBase);
28. establecerAltura(unaAltura);
29.
30. }
31.
32.
33. Triangulo::~Triangulo()
34. {
35. // Cuerpo vacío
36. }
37.
38.
39. void Triangulo::establecerBase(double unaBase)
40. {
41. // Validar la base
42. if (unaBase >= 0.0)
43. {
44. base = unaBase;
45. }
46. else
47. {
48. base = 0.0;
49.
50. }
51.
52. }
53.
54.
55. void Triangulo::establecerAltura(double unaAltura)
56. {
57. // Validar la altura
58. if (unaAltura >= 0.0)
59. {
60. altura = unaAltura;
61. }
62. else
63. {
64. altura = 0.0;
65.
66. }
67.
68. }
69.
70.
71. // Calcula el área del Triangulo
72. double Triangulo::calcularArea()
73. {
74. return (obtenerBase() * obtenerAltura()) / 2.0;
75.
76. }
--- 46 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
77.
78.
79. // Imprime un objeto de la clase Triangulo
80. void Triangulo::imprimir()
81. {
82. Forma2D::imprimir();
83.
84. cout << "Base: " << obtenerBase() << ", Altura: "
85. << obtenerAltura() << ", Area: "
86. << calcularArea() << endl;
87.
88. }
--- 47 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 48 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
7. #include "forma3d.h"
8.
9.
10. class Esfera : public Forma3D
11. {
12. public:
13. Esfera();
14. explicit Esfera(double unRadio);
15. Esfera(std::string unTipo, double unRadio);
16.
17. virtual ~Esfera();
18.
19. double obtenerRadio() { return radio; }
20. void establecerRadio(double unRadio);
21.
22. virtual double calcularArea() override;
23. virtual double calcularVolumen() override;
24. virtual void imprimir() override;
25. protected:
26. private:
27. double radio;
28. };
29.
30. #endif // ESFERA_H
--- 49 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
27. }
28.
29.
30. Esfera::~Esfera()
31. {
32. // Cuerpo vacío
33. }
34.
35.
36. void Esfera::establecerRadio(double unRadio)
37. {
38. // Validar el radio
39. if (unRadio >= 0.0)
40. {
41. radio = unRadio;
42. }
43. else
44. {
45. radio = 0.0;
46.
47. }
48.
49. }
50.
51.
52. // Calcula el área de la esfera
53. double Esfera::calcularArea()
54. {
55. return PI * obtenerRadio() * obtenerRadio() * 4;
56.
57. }
58.
59.
60. // Calcula el volumen de la esfera
61. double Esfera::calcularVolumen()
62. {
63. double r = obtenerRadio();
64.
65. return PI * r * r * r * 4 / 3; 66.
67. }
68.
69.
70. // Imprime un objeto de la clase Esfera
71. void Esfera::imprimir()
72. {
73. Forma3D::imprimir();
74.
75. cout << "Radio: " << obtenerRadio() << ", Area: "
76. << calcularArea() << endl;
77.
78. }
--- 50 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 51 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 52 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
67.
68.
69. // Imprime un objeto de la clase Cubo
70. void Cubo::imprimir()
71. {
72. Forma3D::imprimir();
73.
74. cout << "Lado: " << obtenerLado() << ", Area: "
75. << calcularArea() << endl;
76.
77. }
--- 53 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 54 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
52. }
53.
54.
55. // Calcula el área del Tetraedro
56. double Tetraedro::calcularArea()
57. {
58. return sqrt(3.0) * obtenerLadoTriangulo() *
59. obtenerLadoTriangulo();
60. }
61.
62.
63. // Calcula el volumen del Tetraedro
64. double Tetraedro::calcularVolumen()
65. {
66. double lado = obtenerLadoTriangulo();
67.
68. return sqrt(2.0) * lado * lado * lado / 12.0;
69.
70. }
71.
72.
73. // Imprime un objeto de la clase Tetraedro
74. void Tetraedro::imprimir()
75. {
76. Forma3D::imprimir();
77.
78. cout << "ladoTriangulo: " << obtenerLadoTriangulo()
79. << ", Area: " << calcularArea() << endl;
80.
81. }
4.4.5. Polimorfismo
En las líneas 4 a 15 de este Listado 33, se incluyen todos los archivos de cabecera
necesarios para acceder a las definiciones de las clases en la jerarquía de herencia de
las formas geométricas. Posteriormente, en las líneas 22 a 35, declaramos un arreglo
de variables de tipo apuntador a objetos de la clase Forma, la clase base de toda la
jerarquía de herencia que hemos estado desarrollando. Al mismo tiempo, instanciamos
dinámicamente dos objetos del tipo de cada una de las seis clases
--- 55 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
39. // Formas 2D
40.
41. formas[0]->establecerColorContorno(SIN_COLOR);
42. formas[0]->establecerColorRelleno(AMARILLO);
43.
--- 56 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
44. formas[1]->establecerColorContorno(NEGRO);
45. formas[1]->establecerColorRelleno(BLANCO);
46.
47. formas[2]->establecerColorContorno(AZUL);
48. formas[2]->establecerColorRelleno(ROJO);
49.
50. formas[3]->establecerColorContorno(CIAN);
51. formas[3]->establecerColorRelleno(ROSA);
52.
53. formas[4]->establecerColorContorno(GRIS_OBSCURO);
54. formas[4]->establecerColorRelleno(NARANJA);
55.
56. formas[5]->establecerColorContorno(GRIS);
57. formas[5]->establecerColorRelleno(MAGENTA);
58.
59. // Formas 3D
60.
61. formas[6]->establecerColorContorno(VERDE);
62. formas[6]->establecerColorRelleno(GRIS_CLARO);
63.
64. formas[7]->establecerColorContorno(GRIS_CLARO);
65. formas[7]->establecerColorRelleno(VERDE);
66.
67. formas[8]->establecerColorContorno(MAGENTA);
68. formas[8]->establecerColorRelleno(GRIS);
69.
70. formas[9]->establecerColorContorno(NARANJA);
71. formas[9]->establecerColorRelleno(GRIS_OBSCURO);
72.
73. formas[10]->establecerColorContorno(ROSA);
74. formas[10]->establecerColorRelleno(CIAN);
75.
76. formas[11]->establecerColorContorno(ROJO);
77. formas[11]->establecerColorRelleno(AZUL);
78.
79. // Configurar la impresión de números de punto flotante
80. cout << fixed << setprecision(2);
81.
82. // Procesar en forma polimórfica los objetos de la clase Forma
83. for(Forma *forma : formas)
84. {
85. forma->imprimir();
86. cout << endl;
87.
88. // Intentar convertir el apuntador a un objeto de la clase
89. // Forma a apuntador a objeto de la clase Forma3D (para
90. // calcular el volumen)
91.
92. Forma3D *forma3d = dynamic_cast<Forma3D *>(forma);
93.
94. if (forma3d != nullptr) // Verdadero para una relación es-un
95. {
96. double volumen = forma3d->calcularVolumen();
97.
98. cout << "... y el volumen es : " << volumen << "\n"
99. << endl;
--- 57 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
100.
101. } // if
102.
103. } // foreach forma
104.
105. return 0;
106.
107. } // main()
--- 58 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 59 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
también de la clase Forma y de la clase Forma2D, las cuales por supuesto no tiene.
En este sentido, las líneas 22 a 35 del Listado 33, realizan precisamente lo que el
inciso d) muestra, asignar a un apuntador a un objeto de una clase base un
apuntador a un objeto de una clase derivada. Posteriormente, en las líneas 37 a 77,
hacemos uso de la parte de las características de la clase Forma que los objetos
en el arreglo tienen, llamando a las funciones miembro que establecen el color del
contorno y el color de relleno para asignarle a cada forma dichos colores.
--- 60 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
Dentro del ciclo for mejorado, la variable forma se emplea para llamar a la función
imprimir() de la parte de las características de la clase Forma que todos los
objetos de las clases derivadas tienen.
--- 61 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
En esta sección presentamos una de las muchas mejoras que el estándar C++11
incluye en el lenguaje. En las líneas 88 a 101 del Listado 33, queremos determinar si el
objeto que estamos procesando mediante al apuntador forma es del tipo de una clase
derivada de la clase Forma3D, esto con la finalidad de calcular el volumen de dicha
forma geométrica. Si el objeto no es del tipo Forma3D (recordemos que un objeto de
una clase derivada es-un objeto de su clase base) no tendría ni declarada ni definida la
función calcularVolumen(). Para tal fin, en la línea 92 usamos el operador
dynamic_cast para intentar la coerción del tipo del apuntador forma, de modo
descendente y dinámico.vii Luego, en la línea 94 verificamos el apuntador devuelto por
Ya solo resta devolver un indicador de éxito al sistema operativo, línea 105 del
Listado 33, y finalizar la ejecución del programa.
vii La coerción es descendente, porque intentamos convertir un apuntador a un objeto de tipo Forma, a un
apuntador a un objeto de tipo Forma3D, y la clase Forma3D se deriva de la clase Forma
(descendemos en el árbol de la jerarquía de herencia). Y es dinámica, porque la coerción de tipo se
intenta realizar al momento de ejecutar el programa, no cuando lo estamos compilando.
viii nullptr es otra de las adiciones al lenguaje en el estándar C++11, es una constante que indica
que un apuntador apunta a nada, pero más segura que la constante NULL a la que los programadores
del lenguaje C están acostumbrados.
--- 62 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 63 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
--- 64 ----
CONALEP MICHOACÁN
2014 [IMPLEMENTACIÓN DE LA POO EN C++]
Referencias
1 Deitel, P. & Deitel, H. (2014) C++ How to Program, 9th. Ed. Boston, Massachusetts: Pearson
Education, Inc.
2 Amdocs. “Object Oriented Concepts.” Consultado: 29 de noviembre de 2013, de
http://pro-cess.co.il/downloads/Dreams_come_true.ppt
--- 65 ----
CONALEP MICHOACÁN