Taller de Computación III

Anuncio
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
1
Taller de Computación III
2do Cuatrimestre 2008
Analista de Sistemas de
Computación
Yatay 240 - Buenos Aires - República Argentina
1 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
TABLA DE CONTENIDOS
OBJETIVO DE ESTE APUNTE ..............................................................................................................................................................4
REQUISITOS PARA APROBAR LA MATERIA..................................................................................................................................5
BIBLIOGRAFÍA ........................................................................................................................................................................................5
UNIDAD 1...................................................................................................................................................................................................6
REGLAS BÁSICAS DE PROGRAMACIÓN........................................................................................................................................6
ESTRUCTURA DE UN PROGRAMA C.................................................................................................................................................8
ESTRUCTURA DE UN PROGRAMA EN C++ .....................................................................................................................................8
¿QUÉ SON ARCHIVOS DE CABECERA? .......................................................................................................................................................8
Inclusión de archivos..........................................................................................................................................................................8
PROGRAMAS MULTIARCHIVO .........................................................................................................................................................8
CONSTRUCCION DE ARCHIVOS PROYECTO .................................................................................................................................8
ABRIR UN PROYECTO ................................................................................................................................................................................8
USO DE LAS MACROS Y CONSTANTES ......................................................................................................................................................8
FORMATO DE SALIDA CON COUT ....................................................................................................................................................8
Manipulador setw ......................................................................................................................................................................................8
Manipulador setbase ................................................................................................................................................................................8
Manipulador setfill ....................................................................................................................................................................................8
Manipulador setprecision .......................................................................................................................................................................8
Manipuladores setiosflags y resetiosflags .........................................................................................................................................8
Manipuladores sin parámetros:............................................................................................................................................................................8
Manipuladores dec, hex y oct ................................................................................................................................................................8
EJEMPLO DE ESTRUCTURAS Y PUNTEROS DE ESTRUCTURAS EN C++ ..................................................................................8
UNIDAD 2 PUNTEROS ...........................................................................................................................................................................8
¿QUÉ ES UN PUNTERO? .............................................................................................................................................................................8
PROBLEMAS CON PUNTEROS ....................................................................................................................................................................8
1-Puntero mal inicializado ................................................................................................................................................................8
GESTION DE MEMORIA......................................................................................................................................................................8
UNIDAD 3 CONCEPTOS DE PROGRAMACIÓN ORIENTADA A OBJETOS ...............................................................................8
¿QUE ES LA PROGRAMACION ORIENTADA A OBJETOS?............................................................................................................8
PROGRAMA ORIENTADO A OBJETOS ..........................................................................................................................................................8
HERENCIA ................................................................................................................................................................................................8
POLIMORFISMO .........................................................................................................................................................................................8
REUTILIZACIÓN.........................................................................................................................................................................................8
UNIDAD 4 CONCEPTOS DE CLASES Y OBJETOS ...........................................................................................................................8
Las Clases En C++.............................................................................................................................................................................8
Atributos y métodos............................................................................................................................................................................8
1.
Implementación de los métodos fuera de la estructura class..................................................................................................8
2.
Métodos (Funciones miembro) insertados ..............................................................................................................................8
Creación y uso de objetos ..................................................................................................................................................................8
Paso de mensajes ...............................................................................................................................................................................8
Visibilidad...........................................................................................................................................................................................8
Publico y Privado ...............................................................................................................................................................................8
La clase (dentro del objeto)................................................................................................................................................................8
Desde fuera del objeto........................................................................................................................................................................8
Categoría de los métodos ...................................................................................................................................................................8
Ejemplo: La clase Punto....................................................................................................................................................................8
Convención de denominaciones ........................................................................................................................................................8
Representación gráfica ......................................................................................................................................................................8
Ejemplo de una clase Cuenta (bancaria) ..........................................................................................................................................8
Uso de la Clase Cuenta ......................................................................................................................................................................8
Que ocurre durante la ejecución .......................................................................................................................................................8
Yatay 240 - Buenos Aires - República Argentina
2 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
EJEMPLOS DE FUNCIONES CON PARÁMETROS CON VALORES POR DEFECTO EN C++.................................................................................8
EJEMPLOS SOBRECARGA DE FUNCIONES EN C++ ......................................................................................................................................8
EJEMPLOS DE PUNTEROS DE ESTRUCTURAS Y PUNTEROS DE OBJETOS EN C++ .........................................................................................8
EJEMPLOS DE FUNCIONES VIRTUALES EN C++ ..........................................................................................................................................8
CABECERAS PROVISTAS POR EL ENTORNO ................................................................................................................................................8
APENDICE A - OBJETOS Y CLASES ...................................................................................................................................................8
A.1 INTRODUCCIÓN ..................................................................................................................................................................................8
A.2 ABSTRACCIÓN DE DATOS ...................................................................................................................................................................8
A.3 CONCEPTO DE CLASE .........................................................................................................................................................................8
A.4 OBJETOS ............................................................................................................................................................................................8
A.5 ACCESO A LOS MIEMBROS DE UNA CLASE ..........................................................................................................................................8
A.6 CLASES VACÍAS ..................................................................................................................................................................................8
A.7 LOS MIEMBROS DATO.........................................................................................................................................................................8
A.8 ÁMBITO DE UNA CLASE ......................................................................................................................................................................8
A.9 ESPECIFICADORES DE ACCESO A LOS MIEMBROS DE UNA CLASE ........................................................................................................8
A.10 FUNCIONES MIEMBRO ......................................................................................................................................................................8
A.11 EL PUNTERO THIS .............................................................................................................................................................................8
A.12 FUNCIONES MIEMBRO ESTÁTICAS ....................................................................................................................................................8
A.13 CONSTRUCTORES .............................................................................................................................................................................8
A.14 DESTRUCTORES ...............................................................................................................................................................................8
A.15 CREACIÓN Y SUPRESIÓN DINÁMICA DE OBJETOS ..............................................................................................................................8
A.16 FUNCIONES AMIGAS .........................................................................................................................................................................8
B.- HERENCIA Y JERARQUIA DE CLASES .......................................................................................................................................8
B.1 INTRODUCCIÓN ..................................................................................................................................................................................8
B.2 CLASES DERIVADAS ...........................................................................................................................................................................8
B.3 CONCEPTOS FUNDAMENTALES DE DERIVACIÓN..................................................................................................................................8
B.4 LA HERENCIA EN C++ ........................................................................................................................................................................8
B.5 CREACIÓN DE UNA CLASE DERIVADA .................................................................................................................................................8
B.6 CLASES DE DERIVACIÓN .....................................................................................................................................................................8
B.7 CONSTRUCTORES Y DESTRUCTORES EN HERENCIA .............................................................................................................................8
B.8 REDEFINICIÓN DE FUNCIONES MIEMBRO HEREDADAS.........................................................................................................................8
B.9 HERENCIA MÚLTIPLE ..........................................................................................................................................................................8
B.10 CONSTRUCTORES Y DESTRUCTORES EN HERENCIA MÚLTIPLE ..........................................................................................................8
B.11 HERENCIA REPETIDA ........................................................................................................................................................................8
B.12 CLASES BASE VIRTUALES .................................................................................................................................................................8
APENDICE DE PUNTEROS Y ARREGLOS .........................................................................................................................................8
DIRECCIÓN ARITMÉTICA ..................................................................................................................................................................8
PUNTEROS DE CARACTERES Y FUNCIONES .................................................................................................................................8
EJEMPLOS DE FUNCIONES QUE MANEJAN CADENAS DE CARACTERES EN C Y C++ ....................................................................................8
EJEMPLO DE UTILIZACIÓN DE PUNTEROS PARA DETERMINAR EL FIN DE UN VECTOR Y TYPEDEF ................................................................8
APENDICE MANEJO DE ARCHIVOS .................................................................................................................................................8
EJEMPLOS DE ARCHIVOS EN LENGUAJE C.................................................................................................................................................8
VERSION CON FREAD Y FWRITE .................................................................................................................................................................8
EJEMPLOS DE ARCHIVOS EN LENGUAJE C++ ............................................................................................................................................8
ERRORES COMUNES CON PUNTEROS Y EN CADENAS DE CARACTERES.......................................................................................................8
3
Yatay 240 - Buenos Aires - República Argentina
3 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
OBJETIVO DE ESTE APUNTE
Mediante este apunte pretendemos aproximarnos al desarrollo de la temática del taller.
Lo hemos organizado de acuerdo a cómo se dictarán las clases teóricas, resaltando el desarrollo de
ejemplos para cada uno de los temas.
Recomendamos su uso durante el transcurso de las clases, y también como material de consulta.
Cada ejemplo planteado fue pensado con el objeto de facilitar la comprensión del tema abordado.
Creemos que es de suma utilidad implementar los ejemplos e ir mejorándolos, hasta adquirir
habilidad en su tratamiento.
Tenemos la esperanza y convicción de que sea amena su lectura.
Este apunte fue desarrollado por los profesores:
Fabián Gentile
Vasquez Daniel
Este material pertenece a la materia Taller de Computación III, de la Carrera Analista de Sistemas de Computación del INSTITUTO DE
TECNOLOGIA ORT.
Todos los derechos reservados. No está permitida la reproducción total o parcial de este apunte, ni su tratamiento informático, ni la
transmisión de ninguna forma o por cualquier medio, ya sea electrónico, mecánico, por fotocopia, por registro u otros métodos, sin el
permiso previo de los titulares. 18 de agosto de 2008
Yatay 240 - Buenos Aires - República Argentina
4 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
REQUISITOS PARA APROBAR LA MATERIA
2 exámenes Parciales. Evaluación grupal de los trabajos prácticos realizados durante el cuatrimestre
entregados en fecha a estipular. Cada trabajo grupal constará de una carpeta indicando claramente el
alcance y desarrollo del trabajo práctico. Proyecto Final entregado antes del fin del cuatrimestre.
BIBLIOGRAFÍA
De lectura obligatoria.
Apuntes provistos por la cátedra y publicaciones recomendadas para cada tema.
Manuales del MS-DOS.
Uso del Turbo C.
Del Editor.
De los lenguajes C y C++.
De lectura optativa.
Lenguaje C Kernigan & Ritchie.
Lenguaje C y C++ Herbert Shildt.
Lenguaje C++ Joyanes Aguilar
Suplementos de informática de diarios, revistas de informática, folletos de eventos informáticos.
Internet.
Yatay 240 - Buenos Aires - República Argentina
5 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
UNIDAD 1
REGLAS BÁSICAS DE PROGRAMACIÓN
Discusión y definición de un conjunto de reglas para la escritura de programas.
Descripción del entorno.
Cuando escribimos un programa debemos tener en cuenta que éste debe trascender en el tiempo,
para lo cual, además de funcionar según el objetivo previsto, debe cumplir una serie de reglas
básicas, las cuales harán posible su mantenimiento.
Pensemos por ejemplo en el programa mediante el cual nos inscribimos para cursar las materias, o
bien con el que nos inscribimos para rendir los exámenes finales. Tratemos de imaginar cuántas
líneas de código tendrán dichos programas, y comparémoslos con los que nosotros escribimos hasta
el momento.
Es probable que nuestros programas no hayan superado las 50 ó 60 líneas, y claro, de compararlo
con alguno de los ejemplos que proponemos más arriba, nos podremos dar cuenta que éstos (los de
arriba) deben ser un poco más complejos.
Si dejamos volar un poco nuestra imaginación y no nos asustan los números grandes podremos
suponer que alguno de esos programas puede llegar a tener 3000 ó 4000 líneas de código.
Surge entonces la necesidad de establecer un conjunto de reglas de programación:
Resolución del problema en papel, a través de diagramas.
Documentación del código a medida que se escribe.
Desarrollo top-down (de lo general a lo particular).
Correcta diagramación:
• Uso de procedimientos y funciones.
• Uso de librerías.
Parametrización adecuada.
Mantenimiento de copias de seguridad (más de una versión).
Uso del DEBUGGER.
Prueba de programas con datos representativos.
El uso de estas reglas proporciona las siguientes ventajas:
Comprensión a futuro (poder comprender los programas).
Fácil mantenimiento (poder modificar los programas ocupando nuestro tiempo sólo en las
nuevas aplicaciones).
Fácil puesta a punto.
Reutilización del código.
Yatay 240 - Buenos Aires - República Argentina
6 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Documentación del código a medida que se escribe
Desarrollaremos ahora diversas técnicas de documentación.
¿Qué es la documentación?
Un programa está terminado cuando realiza aquella función para la cual fue pensado y además está
documentado adecuadamente. Documentar es básicamente insertar líneas de comentarios entre las
líneas de código del programa. Un programa que no tenga comentarios no está concluido.
La auto documentación de un programa se implementa con líneas de comentarios en el mismo. En C
utilizamos los símbolos /* para indicar que comienza un párrafo de comentarios e indicamos mediante
los símbolos */ que finalizan los mismos.
En C++ los símbolos // indican el comentario de una sola línea y puede ir cualquier parte de la misma.
Ejemplo:
// este es un comentario en C++
/* este es un comentario en C y en C++ */
Esta es información para el programador, motivo por el cual no es analizada por el compilador ni
tampoco por el usuario de los programas.
Agregaremos comentarios en:
Inicio del programa. Carátula
Definición de tipos y variables
Procedimientos y funciones (que reciben y que devuelven las variables)
Definición de variables locales
Procesos (si hay algún cálculo con una determinada formula)
Veamos cada caso:
Inicio del programa. Carátula
Todo programa, así como cualquier empresa, familia, o producto debe ser unívocamente identificado.
Esto permite que cualquier programador, al leer las primeras líneas del código, pueda saber de qué
se trata.
Debemos iniciar el mismo con una carátula, donde se indique:
Nombre del programa (no necesariamente debe coincidir con el nombre del archivo).
Objetivos del programa.
Nombre del/los autor/es, curso y grupo.
Fecha de inicio y fecha de entrega.
Renglones para indicar las últimas modificaciones realizadas (esto último permite llevar
una historia del programa).
Yatay 240 - Buenos Aires - República Argentina
7 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Ejemplo de carátula:
/* Nombre del programa:
Objetivos:
Curso:
Autores:
Grupo
Fecha inicio:
Fecha de entrega:
Modificaciones:
fecha autor motivo
*/
Definición de tipos y variables
Cuando definimos tipos o variables debemos utilizar un nombre mnemotécnico, y describir mediante
un comentario cuál es su utilidad.
Ejemplo:
char s[30]; /* cadena para almacenar nombres */
struct tydato { /*para recibir valores de entrada */
char nombre[30] ;
int Edad ;
};
/* para definir el origen de los datos (puede ser un array, o un file) */
float fecha ; /* Par la fecha del Díaz/
int cont ; /* para contar los juegos ingresados */
Funciones (Inicio y Final)
Al inicio de cada función de nuestro programa debemos indicar el objetivo del mismo, así como
también qué recibe y qué devuelve.
Ejemplo:
/*-----------------------------------------------------------------------------------------------------------------------------*/
void leer(char *origen, int dato, int fin) ;
/* Lectura de datos desde el origen.
RECIBE : ORIGEN: ES EL ORIGEN DE LOS DATOS
Devuelve: Dato: es el dato leído
Fin: 0 si leí un dato,1 si no hay mas datos */
{
.....
} (Los tipos utilizados ya fueron definidos anteriormente).
/*-----------------------------------------------------------------------------------------------------------------------------*/
ESTRUCTURA DE UN PROGRAMA C
En general los programas C se organizan como un conjunto de funciones que se suelen compilar
independientemente de cualquier programa. Cuando estas funciones se necesitan, se enlazan con el archivo
fuente que contiene la función main(). Una ventaja importante es que las funciones se convierten generalmente
en recursos de propósito general que sirven a un número de programas diferentes. Actualmente, en la mayoría
de los sistemas operativos, los archivos compilados independientemente se pueden comprimir en bibliotecas
en las que realizan la misma función pero en un formato que ahorra espacio de disco.
figuras.h
/* archivo figuras.h
figuras.c
demofiguras.c
archivo de cabecera */
#ifndef FIGURAS_H
#define FIGURAS_H
/*archivo demofiguras.c
programa principal */
typedef struct RECTANGULO
{
double x1, y1, x2, y2;
};
/* estructuras de datos y
funciones */
#endif
#include <stdio.h>
#include <figuras.h>
int main(void)
{
.....
}
Yatay 240 - Buenos Aires - República Argentina
8 de 76
/* archivo figuras.c
cálculo área de una figura
#include <math.h>
#include<figuras.h>
double calcular_area(...)
{
…
}
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
La Figura 13-3 muestra la estructura de un programa C.
Un programa típico C se organiza en uno o más archivos fuente, o módulos. Cada archivo tiene una estructura
similar, con comentarios, directivas del preprocesador, declaraciones de variables y funciones, y sus
definiciones. Algunos archivos son simplemente un conjunto de declaraciones que se utilizan en otros archivos
a través de la directiva #include del preprocesador C. Estos archivos se conocen normalmente como archivos
de cabecera y tienen nombres que terminan con la extensión .h Así, en el archivo figuras.h es un archivo de
cabecera que declara estructuras de datos comunes y funciones para el programa. Otro archivo figuras.c
define las funciones, y un tercer archivo demofiguras.c implementa la función main( ). Esta función es la que
sirve para comenzar la ejecución de un programa C. Los archivos con nombre que terminan en C son los
archivos fuente en los que se define las funciones necesarias para su programa. En general, los archivos
fuente contienen definiciones de muchas funciones.
Para crear un programa ejecutable se deben compilar y enlazar los archivos fuentes. Los pasos exactos
para construir programas a partir de archivos fuente C dependen del compilador y el sistema operativo.
ESTRUCTURA DE UN PROGRAMA EN C++
En general, un programa C++ se organiza como un conjunto de archivos de cabecera y archivos fuente, al igual
que sucede con los programas escritos en C.
Definición cabecera clase: trabajador.h
class trabajador
{
...
};
implementación clase: trabajador.cpp
#include "trabajo.h"
....
trabajador::trabajador (int l, char *n, float s)
{
...
}
void trabajador::imprimir(float horas);
{
...
}
archivo principal : salario.cpp
#include "trabajador.h"
void main( ){
trabajador t;
...
}
Estructura de un programa C++ que posee clases.
El archivo del programa principal es salario.cpp, un archivo de cabecera que declara la clase trabajador,
trabajador.h y otro archivo que implementa esa clase trabajador.cpp.
Los archivos de cabecera C + + de Borland normalmente tienen la extensión .h otros compiladores tales
como los soportados por UNIX tienen también la extensión . h y los compiladores de Zortech tienen la extensión .hpp.
Los archivos C++ de Borland tienen una extensión .cpp. UNIX utiliza la extensión .c y Zortech utiliza la
expresión .cpp.
Yatay 240 - Buenos Aires - República Argentina
9 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Consideremos una aplicación sencilla que calcule el salario de un trabajador en función del número de horas
trabajadas.
II trabajador.h : definición de la clase trabajador
#ifndef TRABAJADOR_H
#define TRABAJADOR_H
class trabajador{
private:
int id;
char nombre[40];
float jornal;
public:
trabajador(int i, char *n, float w);
void imprimir(float horas);
};
#endif
El archivo fuente trabajador.cpp contiene las implementaciones de la clase trabajador.
// archivo trabajador.cpp
#include <stdio.h>
#include <string.h>
#include "trabajador.h"
trabajador::trabajador(int i, char *, float w)
{
id = i;
strcpy(nombre, n);
jornal=w;
}
void trabajador::imprimir(float horas)
{
printf("Empleado #%d %s\n",id, nombre;
printf("Horas trabajadas: %8.2t\n",horas);
printf("Salario pagado: $ %9.2f\\",horas * jornal);
}
¿Qué son archivos de cabecera?
Los archivos de cabecera en C contienen definiciones, tales como los tipos y nombres de variables
externas, definiciones de estructuras, constantes, macros y prototipos de funciones. Las declaraciones de
variables se deben situar en archivos de código junto con las implementaciones de las funciones.
C++ soporta además de estos archivos de cabecera, declaraciones y clases y funciones en línea.
Las clases se manipulan como estructuras. Una declaración de una clase se sitúa en un archivo de cabecera al cual
se puede acceder desde otros archivos fuente. Las implementaciones de las clases se sitúan en un archivo fuente
independiente. Los archivos trabajador.h y trabajador.cpp son ejemplos de archivos de cabecera y de código
fuente.
Las funciones en línea son un tipo especial de función similar a las macros. Al igual que las macros, las
funciones en línea se pueden situar o bien en archivos de cabeceras o en archivos fuente. Si se desea que una
función en línea sea global en un programa multiarchivo, se debe situar en un archivo de cabecera e incluir
esta cabecera en otros archivos, tal como las macros globales.
}
// archivo ejempo.h
inline int max(int a, int b)
{
if(a > b)
return a;
else
return b;
}
const int Longitud = 100;
//archivo prog.cpp
#include
"ejemplo.h"
void main( )
{
...
if (max(xi, x2) < longitud);
...
}
Inclusión de archivos
C++ al igual que C permite escribir programas modulares mediante la directiva #include. El procesador permite
Yatay 240 - Buenos Aires - República Argentina
10 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
incluir el contenido de un archivo en el código fuente, con dos formatos diferentes:
#include <stdio.h>
#include <mostream.h>
#include "trabajador.h"
Estas tres líneas son sustituidas lógicamente por el contenido de los archivos de cabecera stdio.h, iostream.h y
trabajador.h. Se dice entonces que se han incluido estos archivos.
Los caracteres <> y "" o sirven para indicar dónde se buscan los archivos de cabecera:
<...> El archivo de cabecera se busca sólo en el directorio por omisión.
(En sistemas UNIX, el directorio por omisión es normalmente /usr/include).
“...” El archivo de cabecera se busca sucesivamente en:
1. El directorio actual, y si no se encuentra allí,
2. En los directorios generales de include.
Se pueden especificar nombres de camino relativos así como sentencias #include. Por ejemplo,
#include <sys\stat.h> indica al compilador que busque stat.h en el directorio sys que es un subdirectorio de
uno de los directorios por omisión.
PROGRAMAS MULTIARCHIVO
Una de las grandes aplicaciones de la compilación separada es la construcción de grandes programas. Hasta
este momento casi todos los programas se compongan de un único archivo; en esta sección y en las
siguientes trataremos de la organización de programas compuestos de múltiples archivos. así como los
métodos que incorporan algunos compiladores para la realización de grandes proyectos que se componen de
diferentes archivos fuente.
A medida que los proyectos de programación son más grandes, es conveniente empaquetar el código en
diferentes archivos fuente o módulos. La división de un proyecto en piezas más pequeñas tiene las siguientes
ventajas:
•
•
•
•
El seguimiento de la lógica de su programa, Si todo el código de un gran proyecto están contenidos en un
único archivo fuente, el tamaño del archivo hará el programa más difícil de seguir. La rotura de los programas en partes o segmentos más pequeños, facilita el diseño global del problema.
El proceso de depuración y modificación de su programa es más difícil. La división de su programa en
diversos archivos fuente facilita el aislamiento de su problema y permite encontrar rápidamente cuales
son los grupos de funciones que producen el problema.
Se pueden desarrollar bibliotecas de funciones. A medida que se desarrollan grandes proyectos, se crean
funciones que se pueden utilizar ampliamente. El agrupamiento de funciones facilita la escritura de
archivos fuentes y su uso en otros proyectos. (Esta característica es típica del lenguaje C).
Desarrollo de biblioteca de clases. Dado que C++ se organiza en clases en lugar de en funciones, y los
programas constan esencialmente de clases, es usual la construcción de bibliotecas de clases por el
usuario y la utilización de bibliotecas estándar diseñadas por los fabricantes de compiladores. Las
bibliotecas de clases tienen un papel más importante en la programación C++ que las bibliotecas de
funciones, ya que necesitará pocos esfuerzos y una mínima cantidad de programación para crear un
producto final. Otra ventaja considerable es que a medida que se dispone de más bibliotecas de clases,
se tendrá más facilidades y posibilidades para resolver un problema especifico de programación,
Funcionalidad de los programas. Es frecuente dividir el programa en archivos separados, de acuerdo a su
funcionalidad. Por ejemplo, un archivo puede manipular el código implicado en gráficos, otro archivo
manipula los procesos matemáticos y un tercer archivo, las operaciones de entrada / salida (E/S).
¿Qué se debe poner en un archivo fuente?
Una vez que se tiene un proyecto bastante grande, es preciso decidir cómo dividir sus funciones en archivos
fuente separados. Necesitará considerar también cómo se pueden depurar, modificar y reutilizar fácilmente
esos archivos fuente; al igual que todo buen proyecto de ingeniería se requiere diseño modular.
Cuando comience a dividir sus funciones en archivos fuente, asegúrese de mantener las funciones
relacionadas en un único archivo fuente. Si por ejemplo, mantiene todas sus funciones de entrada de datos en
un archivo fuente, tendrá sólo un archivo fuente a depurar cuando tenga un problema de entrada. Con todas
las funciones relacionadas en un archivo fuente, no tendrá que buscar a través de páginas de listados para
encontrar la función que necesita corregir. Otra estrategia es mantener los datos necesarios para una función
en el mismo archivo fuente que la función; esta acción le ayuda a prevenir cambios no intencionados en los
valores de los datos.
Yatay 240 - Buenos Aires - República Argentina
11 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Se deben crear grupos de funciones que se puedan modificar fácilmente. Por ejemplo, si todas las
funciones de ordenación de un proyecto de base de datos están en un archivo fuente, se pueden hacer
cambios en estas funciones sin afectar a otras partes del proyecto. Organice sus funciones de modo que todas
las modificaciones a una función se puedan hacer en un archivo fuente,
Divida sus funciones de modo que tenga grupos de funciones que puedan ser incluidas fácilmente en otros
programas. A medida que se desarrollan programas más grandes y potentes, es conveniente crear funciones
que sean útiles en gran numero de programas. La descomposición de estas funciones en grupos facilita la
reutilización de las funciones en otros proyectos de programación.
Sin embargo, debe tener presente que sólo puede tener un archivo fuente con una función main(). Se
pueden situar las funciones que se desee en ese archivo fuente, pero uno y sólo un archivo fuente puede
contener una función mamo cuyo único propósito es llamar a las otras funciones que sean necesarias. Algunos
proyectos se suelen diseñar de modo que el archivo fuente contiene todo el código especializado de ese
proyecto y cualquier otro archivo fuente se incluye a medida que sea necesario,
CONSTRUCCION DE ARCHIVOS PROYECTO
La mayoría de los actuales compiladores C++, entre ellos Turbo C + + y Borland C++, disponen de una
utilidad que se suele denominar project, que automatiza el proceso de desarrollo de un programa
multiarchivo.
Cuando se tiene un proyecto de programación que utiliza más de un archivo fuente, se necesita crear un
archivo proyecto. Este archivo proyecto, se crea y contiene los nombres de todos los archivos que se
combinaran en el programa ejecutable final.
Supongamos, por ejemplo que ha comprado un archivo de una clase denominada TESTLIA (archivo de
biblioteca) cuyo archivo de cabecera es TEST. H. Su programa fuente DEMO .CPP utiliza las clases de la
biblioteca. Se pueden combinar todos estos archivos en un único programa ejecutable:
Test.h
Archivo
de cabecera
de constructor
de software
Test.obj
Archivo
objeto
constructor de
software
Demo.cpp
Demo.h
Compilador
Archivo
de cabecera
escrito por
usuario
Demo.obj
test.lib
Archivo de
biblioteca
Enlazador
Enlazador
Demo.exe
FIGURA 13-6. Aplicaciones de programa multiarchivo.
La creación de un archivo proyecto requiere tres etapas
1. Crear un nuevo archivo proyecto.
2. Añadir archivos fuente al archivo proyecto.
3. Construir el archivo ejecutable proyecto (el archivo .EXE, en DOS)
Antes de comenzar el proceso, verifique que los archivos componentes están en el mismo directorio
(normalmente se creará un directorio independiente para el proyecto, y así evitar una confusión). Asimismo,
debe incorporar a su archivo fuente DEMO.CPP el archivo de cabecera TEST.H con una sentencia #include:
#include “TEST.H”
Yatay 240 - Buenos Aires - República Argentina
12 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Abrir un proyecto
Para acceder a las funciones de administración de un proyecto, se debe abrir el menú Project <caso de
compilador Borland/Turbo C++) y seleccionar la opción Open, Project para crear un nuevo archivo proyecto.
Con la orden Open se abre un proyecto existente o se asigna un nombre a un nuevo proyecto. Después
deseleccionar Open Project, aparece el cuadro de diálogo Open Project File. En el cuadro de diálogo, teclee el
nombre y camino de nuevo archivo proyecto. Si lo prefiere utilice el cuadro Files para moverse al directorio que
contiene el archivo proyecto.
FIGURA 13-7. Cuadro de diálogo
Open Project File.
Se debe dar al archivo el mismo nombre que desea utilizar en su programa final ejecutable, pero con la
extensión .PRJ en lugar de .EXE. Por consiguiente, si desea que el archivo ejecutable se llame DEMO.EXE,
escriba el nombre DEMO. PRJ. Tras aceptar la entrada haciendo clic en el icono Ok o pulsando la tecla Intro
(Enter), aparecerá otra ventana llamada Project DEMO (Figura 13-8).
FIGURA 13-8. Pantalla de archivos proyecto.
En este momento ha terminado la primera etapa en la creación de un proyecto: ha creado el nuevo archivo
proyecto. A continuación se necesita realizar la segunda etapa, añadir los archivos fuente que se utilizan en el
proyecto.
Yatay 240 - Buenos Aires - República Argentina
13 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Añadir archivos fuente
Una vez que se ha abierto un archivo proyecto, se puede acceder a diferentes opciones del menu Project,
incluyendo Add ítem, Delete ítem e Include Files. Para comenzar a añadir archivos fuente al proyecto,
seleccione la opción Add ítem se visualizará un cuadro de diálogo Add to Project List. Existen dos medios para
seleccionar archivos en este cuadro de diálogo; primero, se puede introducir el nombre del archivo en el
cuadro de entrada; segundo, se puede seleccionar un archivo del cuadro de lista de archivos. Una vez que se
selecciona el archivo, utilizar el botón Add para añadir ese archivo al proyecto.
No deberá contener
archivos de cabecera
(*.h) pues daria error
de linkeo
Se podrán incluir
archivos fuentes y
objetos (*.cpp, *.c *.o)
FIGURA 13-9.
Cuadro de diálogo Add to Project List.
Seleccione el botón Cancel cuando haya terminado de añadir archivos al proyecto. El botón Cancel le
devuelve a la pantalla principal del proyecto.
Cuando la ventana proyecto está activa, la línea de estado de la parte inferior de la pantalla muestra las
diferentes acciones que se pueden realizar. Una vez que se ha creado el archivo proyecto y añadido los
archivos fuente a la lista proyecto, el paso final es la compilación del proyecto.
Historia del lenguaje C
El lenguaje C es un lenguaje de nivel medio, esto significa que está mitad de la escala en el grado de parecido
al lenguaje humano, respecto del lenguaje de máquina.
El lenguaje C fue inventado e implementado por Dennis Ritchie en una computadora DEC PDP-11 que
utilizaba UNIX como sistema operativo. El lenguaje C es la continuación del desarrollo de un lenguaje llamado
BCPL creado por Martín Richards, a su vez ambos influenciaron la creación del un lenguaje llamado B. En los
años 70 el lenguaje B llevo al desarrollo del lenguaje C,
En el año 1978, se publica el libro The C languaje Programming de los autores Kerningan y Ritchie. Este nuevo
lenguaje tuvo una amplia aceptación en el mercado de computación y un éxito incomparable, principalmente
por su gran portabilidad entre distintas plataformas propietarias. Esto significa que un programa escrito en una
computadora, por ejemplo IBM se podía compilar y correr en otra de otra marca sin modificación alguna en su
código fuente.
Yatay 240 - Buenos Aires - República Argentina
14 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Por su parte y a los efecto de evitar la aparición de versiones diversas del lenguaje C, el comité ANSI,
American National Standard Institute de USA, declararon un standard para C en el año 1983. Este standard
contenía todos los comandos del lenguaje aceptados para todas las plataformas. Esto incluye tan solo 32
palabras reservadas. Un hecho destacable del lenguaje es que permite el manejo a nivel de Bits.
C++ es la evolución del C incorporando conceptos de la programación orientada a objetos.
Características principales
•
•
•
•
•
•
•
•
•
•
Débilmente tipado
Interfase e implementación de funciones separadas (.h y .cpp)
Al asignar variables de distintos tipos el casting se hace implícito
Los vectores comienzan en cero
Dentro de la condición de un if o un bucle se pueden realizar operaciones
No hace distinción entre funciones y procedimientos, todo son funciones
Posee funciones inline. El código de la función es reemplazado en cada llamada a la misma por el
compilador. Incrementa la performance haciendo mas grande el ejecutable
Posee precompilador
Soporta sobrecarga de funciones, es decir, se puede definir una función con el mismo nombre y
distintos parámetros y el compilador va a llamar a la correcta
Se manejan proyectos en el cual se incluyen todos los cpp del mismo. En cada proyecto solo debe
haber un main() que es el lugar de inicio del programa.
El C/C++ es ideal para aplicaciones en las cuales se necesite acceso directo al hardware o en aplicaciones en
tiempo real.
UNIDAD 3 TIPOS DE DATOS
Uso de las Macros y Constantes
#include <iostream.h>
#define escribe cout
const int pi =3.1416;
void main() /* Calcula el perímetro */
{
int r;
escribe<<"Introduce el radio: ";
cin>> r;
escribe<<"El perímetro es: "<< 2 * pi * r;
}
Un macro no es una constante ya que no ocupa espacio en memoria.
Es reeplazado antes de compilar por lo que es una directiva de preprocesador
Una constante por otro lado si ocupa un espacio en memoria
En el ejemplo el compilador nunca encuentra escribe ya que es reemplazado por cout antes de compilar
Yatay 240 - Buenos Aires - República Argentina
15 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
FORMATO DE SALIDA CON COUT
Un medio de formatear la salida es usar manipuladores, que son funciones especiales que sirven para cambiar
la apariencia de una operación de salida o entrada de un stream. Su efecto sólo es válido para una operación
de entrada o salida. Para usar estos manipuladores es necesario incluir el fichero de cabecera iomanip
(iomanip.h).
Manipuladores con parámetros:
Existen seis de estas funciones manipuladoras con parametros: setw, setbase, setfill, setprecision,
setiosflags y resetiosflags.
Manipulador setw
Permite cambiar la anchura en caracteres de la siguiente salida de cout.
Por ejemplo:
#include <iostream.h>
#include <iomanip.h>
void main() {
int x = 123, y = 432;
cout << "#" << setw(6) << x << "#" << setw(12) << y << "#" << endl;
}
La salida tendrá este aspecto:
#
123#
432#
Manipulador setbase
Permite cambiar la base de numeración que se usará para la salida. Sólo se admiten tres valores: 8, 10 y 16, es
decir, octal, decimal y hexadecimal.
Por ejemplo:
#include <iostream.h>
#include <iomanip.h>
void main() {
int x = 123;
cout << "#" << setbase(8) << x << "#" << setbase(10) << x
<< "#" << setbase(16) << x << "#" << endl;
}
La salida tendrá este aspecto:
#173#123#7b#
Manipulador setfill
Permite especificar el carácter de relleno cuando la anchura especificada sea mayor de la necesaria para
mostrar la salida.
Por ejemplo:
#include <iostream.h>
#include <iomanip.h>
void main() {
int x = 123;
cout << "#" << setw(8) << setfill('0') << x << "#" << endl;
cout << "#" << setw(8) << setfill('%') << x << "#" << endl;
}
La salida tendrá este aspecto:
#00000123#
#%%%%%123#
Yatay 240 - Buenos Aires - República Argentina
16 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Manipulador setprecision
Permite especificar el número de dígitos significativos que se muestran cuando se imprimen números en punto
flotante: float o double.
Por ejemplo:
#include <iostream.h>
#include <iomanip.h>
void main() {
float x = 121.0/3;
cout << "#" << setprecision(3) << x << "#" << endl;
cout << "#" << setprecision(1) << x << "#" << endl;
}
La salida tendrá este aspecto:
#40.3#
#4e+01#
Manipuladores setiosflags y resetiosflags
Permiten activar o desactivar, respectivamente, los flags de formato de salida.
Existen quince flags de formato a los que se puede acceder mediante un enum definido en la clase ios:
flag
Acción
skipws
ignora espacios en operaciones de lectura
left
ajusta la salida a la izquierda
right
ajusta la salida a la derecha
internal
deja hueco después del signo o el indicador de base
dec
conversión a decimal
oct
conversión a octal
hex
conversión a hexadecimal
showbase muestra el indicador de base en la salida
showpoint muestra el punto decimal en salidas en punto flotante
uppercase muestra las salidas hexadecimales en mayúsculas
showpos
muestra el signo '+' en enteros positivos
scientific
muestra los números en punto flotante en notación exponencial
fixed
usa el punto decimal fijo para números en punto flotante
unitbuf
vacía todos los buffers después de una inserción
stdio
vacía los buffers stdout y stderr después de una inserción
Veamos un ejemplo:
#include <iostream.h>
#include <iomanip.h>
void main() {
float x = 121.0/3;
int y = 123;
cout << "#" << setiosflags(ios::left) << setw(12) << setprecision(4)
<< x << "#" << endl;
cout << "#" << resetiosflags(ios::left | ios::dec)
<< setiosflags(ios::hex | ios::showbase | ios::right)
<< setw(8) << y << "#" << endl;
}
La salida tendrá este aspecto:
#40.33
#
#
0x7b#
Yatay 240 - Buenos Aires - República Argentina
17 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Manipuladores sin parámetros:
Existe otro tipo de manipuladores que no requieren parámetros, y que ofrecen prácticamente la misma funcionalidad que
los anteriores. La diferencia es que los cambios son permanentes, es decir, no sólo afectan a la siguiente salida, sino a
todas las salidas hasta que se vuelva a modificar el formato afectado.
Manipuladores dec, hex y oct
Permite cambiar la base de numeración de las salidas de enteros, supongo que resulta evidente, pero de todos
modos lo diré.
Función
Dec
Hex
Oct
Acción
Cambia la base de numeración a decimal
Cambia la base de numeración a hexadecimal
Cambia la base de numeración a octal
El cambio persiste hasta un nuevo cambio de base. Ejemplo:
#include <iostream.h>
void main() {
int a = 123, c = 432, b = 543;
cout <<
<<
cout <<
<<
cout <<
<<
"Decimal:
" << dec
", " << c << endl;
"Hexadecimal: " << hex
", " << c << endl;
"Octal:
" << oct
", " << c << endl;
<< a << ", " << b
<< a << ", " << b
<< a << ", " << b
}
La salida tendrá éste aspecto:
Decimal:
123, 543, 432
Hexadecimal: 7b, 21f, 1b0
Octal:
173, 1037, 660
Yatay 240 - Buenos Aires - República Argentina
18 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
EJEMPLO DE ESTRUCTURAS Y PUNTEROS DE ESTRUCTURAS EN C++
#include <iostream.h>
#include <string.h>
#include <conio.h>
struct rec {
int cod;
char nom[20];
};
void veoregistro(struct rec *p);
//función con un parámetro puntero de estructura
void main(){
struct rec registro;
struct rec *pregistro;
// inicializar en C++ pregistro = new rec;
// inicializar en C pregistro = malloc(sizeof(struct rec));
clrscr();
registro.cod=10;
strcpy(registro.nom,"pepe");
veoregistro(&registro);
cout<<”cod”<< registro.cod<<”nom”<<registro.nom << endl;
pregistro=&registro; // inicializo el puntero
pregistro->cod=1;
strcpy(pregistro->nom,"jose");
cout<<"cod ”<<pregistro->cod <<”nombre"<<pregistro->nom << endl;
veoregistro(pregistro);
// delete pregistro; libero memoria en C++
// free(pregistro); libero memoria en C
getch();
}
void veoregistro(struct rec *p){
cout<<"cod" <<p->cod << "nombre"<< p->nom<<"\n"
}
Yatay 240 - Buenos Aires - República Argentina
19 de 76
;
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
UNIDAD 2 PUNTEROS
¿Qué es un puntero?
Un puntero es simplemente una variable cuyo contenido es una dirección de memoria.
En la práctica, los punteros suelen usarse para direccionar un tipo de dato en particular. Por
esta razón, y también para saber como direccionar el dato, en C se suele asociar al puntero el tipo de
dato que se va a direccionar.
Un puntero se define anteponiendo un * al nombre de la variable, en su definición (Ej: int *a;).
Es importante recordar que en C, ninguna variable es inicializada por defecto, salvo que se
indique lo contrario. De la misma forma, un puntero, al ser creado, contendrá una dirección de
memoria cualquiera. Si se esta programando en una computadora sin modo protegido (D.O.S., por
ejemplo), toda la memoria es direccionable, es decir que se puede leer/sobreescribir toda la memoria
de la PC, incluyendo el sistema operativo. En modo protegido, direccionar una posición de memoria
inválida producirá un mensaje de error, conocido en Windows como 'General Protection Fault'.
Veamos un par de ejemplos:
int *a;
a es una variable que almacenará una dirección de memoria, en tanto que *a será el entero
contenido de dicha dirección de memoria.
Por ejemplo, supongamos que a tenga el valor de la dirección de memoria 2032, y *a tenga el
valor 50:
El operador &, antepuesto a una variable devuelve la dirección de dicha variable, y se lo llama
operador de indirección. En nuestro ejemplo tendremos:
Tipo
contenido
dirección
memoria
entero
Variable
Tipo de variable
a
puntero a entero
(int *)
entero
(int)
puntero a un puntero a dirección
entero
memoria
(int **)
*a
&a
de contenido
de 2032
50
de 1000
Veamos otro ejemplo:
Yatay 240 - Buenos Aires - República Argentina
20 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
#include <stdio.h>
void main(void){
/* Definición de las variables */
int a;
int *pa;
a = 4;
pa = &a;
*pa = 2;
printf (“%d”, a);función de salida por pantalla del lenguaje C se encuentra en stdio.h
}
Este programa imprimirá el valor 2
En este ejemplo, pa es un puntero a una variable de tipo entero, es decir, una variable que
contendrá una dirección de memoria en donde se almacenará un entero.
En la línea 6 se define una variable a que guardará una variable de tipo entero, y a la cual le
asigno el valor 4, en la línea 9 del código
&a será la dirección de dicha variable. Así, lo que estoy haciendo en la línea 10 del ejemplo es
cargar en pa la dirección de la variable a. Lo que se tiene en este momento es lo siguiente:
Cuando a continuación hago referencia a *pa, me estoy refiriendo a la dirección apuntada por
pa, que en este caso será a.
¿Puedo preguntar ahora que es &pa? Pues bien, es la dirección de memoria donde está
almacenada la variable pa, que a su vez es la dirección de memoria de un entero, es decir, &pa es un
puntero a un puntero a una variable de tipo entero.
En este caso podría escribirse:
int **ppa;
ppa = &pa;
es decir que pueden definirse punteros a punteros a un tipo de variable, y así sucesivamente,
aunque en la práctica sólo se usan a lo sumo doble punteros.
Es común utilizar un caracter ‘p’ como primer letra del nombre de una variable de tipo puntero,
para tener en claro que se trata de un puntero. De idéntica forma, se suele usar pp al trabajar con
doble punteros, y así sucesivamente.
¿Tendría sentido preguntarse por &&a?
Pues no, de ninguna manera. a es una variable que está almacenada en una posición de
memoria, conocida por el programa. Con &a puedo conocer dicha posición, pero &&a no tiene ningún
sentido.
Yatay 240 - Buenos Aires - República Argentina
21 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
//ejemplo variables mal utilizados
#include <stdio.h>
#include <conio.h>
void main(){
int i;
int j;
clrscr();
i= i + 10 ; // i no esta inicializada por lo tanto le sumo 10 a un valor desconocido
j=200;
// j recibe un valor y es inicializada
printf("el contenido de i es:%i y la direccion en memoria es %p\n",i,&i);
printf("el contenido de j es:%i y la direccion en memoria es %p\n",j,&j);
}
#include <stdio.h>
#include <conio.h>
void main(){
int i;
int *pi;
clrscr();
printf("el contenido de i es:%i y la direccion en memoria es %p\n",i,&i);
printf("el contenido de *pi es:%i y la direccion en memoria es %p\n",*pi,pi);
}
esta es la salida
el contenido de i es:4523 y la direccion en memoria es FFF4
el contenido de *pi es:767 y la direccion en memoria es 03B6
la variable i no tiene valor inicial pero su direccion en memoria es valida
la variable pi no tiene valor inicial por lo que su direccion en memoria no es valida
Problemas Con Punteros
1-Puntero mal inicializado
este error es el mas común y produce errores graves de ejecución como ser: el programa aborta su ejecución y el
sistema operativo continua ejecutándose, el programa aborta y bloquea la maquina sin posibilidad de continuar la
ejecución de ningún programa
ej :
int main(){
int *p;
*p=10;
printf(“el valor de *p es %i”, *p);
}
Yatay 240 - Buenos Aires - República Argentina
22 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
GESTION DE MEMORIA
Variables y Constantes
Todas la operaciones de asignación de memoria se gestionan a través del sistema operativo subyacente a la
aplicación.
Para comprender mejor este manejo, construyamos una tabla de variables y constantes (TVC) con la siguiente
estructura
Variable/
Constante
Tipo
Tamaño
Comienzo
Contenido
Por su parte consideremos la memoria de cómo una cuadricula con las siguientes características
• Cada posición tiene capacidad de almacenar un Byte
• Cada posición se identifica solo por su posición de comienzo
• Las posiciones se cuentan en Hexadecimal
Sea nuestro programa
void main(){
int a;
char b;
....
}
TVC
1
2
Variable/
Constante
a
b
Tipo
Tamaño Comienzo
Bytes
Int
2
01h
Char 1
03h
Contenido
????
????
1. La aplicación solicita al sistema operativo espacio en memoria para ubicar (allocate) 2 bytes.
Memoria
???????? ?????????
?????????
01h
02h
03h
04h
05h
06h
07h
08h
09h
Ah
Bh
Ch
Dh
Eh
Fh
Nótese que tanto a como b, no tiene un contenido valido, si bien pueden operar sobre estas variables el valor
obtenido carece absolutamente de sentido, ya que la variable no esta inicializada
Sea nuestro programa
main(){
int a;
char b;
a=3;
b=’c’;
....
}
Variable/
Constante
Tipo
Tamaño
Bytes
Yatay 240 - Buenos Aires - República Argentina
Comienzo
Contenido
23 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
1
2
a
b
Int
Char
00000000
01h
06h
Bh
00000011
02h
07h
Ch
2
1
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
01h
03h
00001100
03h
08h
Dh
3
‘c’
04h
09h
Eh
05h
Ah
Fh
Nótese que tanto a como b, ahora tienen un contenido válido y es posible operar sobre ellas con seguridad
Printf(“%d”, a) ;
Devuelve 3, el calificador “%d” lee un valor binario de 2 bytes y lo transforma en entero a los efectos de
imprimirlo.
Printf(“%d”, &a)
Devuelve 01h
Nota:
Las operaciones de asignación de memoria vistas hasta aquí se las conoce como EARLY BINDING o Ligadura
temprana. Esto significa que el compilador conoce antes de ejecutar la posición que ocupará cada variable
antes de comenzar la ejecución.
Punteros
Los punteros son un grupo de variables especiales sumamente utilizadas en C, se utilizan para almacenar la
dirección de memoria que ocupa de otra variable y ocupan 4 bytes
main(){
int a;
char b;
char *p
a=3 ;
b=’c’;
...
}
1
2
3
Variable/
Constante
a
b
*p
Tipo
Tamaño
Bytes
Int
2
Char 1
Char 4
Comienzo
Contenido
01h
03h
04h
3
‘c’
?????
00000000
01h
?????????
06h
00000010
02h
????????
07h
00001100
03h
????????
04h
????????
05h
08h
09h
Ah
Bh
Ch
Dh
Eh
Fh
En este caso *p es un puntero que apunta a una posición de memoria que contiene 1 byte de tipo Char.
Nótese que al igual que con los ejemplos anteriores *p no tiene un valor valido por no estar inicializado.
Los punteros se puede inicializar de dos maneras:
• Copiando la dirección de memoria de otra variable
• Por medio del operador NEW
Yatay 240 - Buenos Aires - República Argentina
24 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Ejemplos
Void main(){
int a;
char b;
char *p
a=3;
b=’c’;
*p = &b;
...
}
Variable/
Constante
A
B
*p
1
2
3
Tipo
Tamaño
Bytes
Int
2
Char 1
Char 4
Comienzo
Contenido
01h
03h
04h
3
‘c’
03h
0000000
01h
0000000
06h
00000010
02h
00000003h
07h
00001100
03h
00000000
04h
00000000
05h
08h
09h
Ah
Bh
Ch
Dh
Eh
Fh
void main(){
int a;
char b;
char *p
a=3 ;
b=’c’ ;
p = new char;
...
}
1
2
3
4
Variable/
Constante
A
B
*p
SIN
NOMBRE
Tipo
Tamaño
Bytes
Int
2
Char 1
Char 4
char 1
Comienzo
Contenido
01h
03h
04h
08h
3
‘c’
08h
¿?
0000000
01h
0000000
06h
00000011
02h
00000008h
07h
‘c’
03h
????????
08h
00000000
04h
00000000
05h
09h
Ah
Bh
Ch
Dh
Eh
Fh
Yatay 240 - Buenos Aires - República Argentina
25 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
El comando new reserva memoria para alojar una variable del tipo/longitud especificado, pero al igual que en
el ejemplo 1, esta variable no esta inicializada y no contiene un valor valido.
void main(){
int a;
char b;
char *p
a=3 ;
b=’c’;
p = new char;
*p = ´a’;
...
}
1
2
3
4
Variable/
Constante
A
B
*p
SIN NOMBRE
0000000
01h
0000000
06h
Bh
Tipo
Int
Char
Char
char
00000011
02h
00000008h
07h
Ch
Tamaño
Bytes
2
1
4
1
‘c’
03h
‘a’
08h
Dh
Comienzo
Contenido
01h
03h
04h
08h
3
‘c’
08h
‘a’
00000000
04h
00000000
05h
09h
Eh
Ah
Fh
Nomenclatura
p es una dirección de memoria = 04h
*p es el contenido de la dirección apuntada por p = ‘a’
*p = ‘a’ Significa a la posición apuntada por p se le asigna ‘a’
p = ‘a’ Es una operación invalida
Yatay 240 - Buenos Aires - República Argentina
26 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
UNIDAD 3 Conceptos de Programación Orientada a Objetos
(Por Joyanes Aguilar c++)
Desde los primitivos: días del nacimiento de las computadoras, los programadores se han dedicado
fundamentalmente a gestionar la complejidad de los programas. Cuando las computadoras se inventaron, la
programación se realizaba con instrucciones binarias de máquina, de modo que se cargaban en memoria a
través de un conjunto de interruptores o a través de un teclado numérico.
A medida que crecían los programas, se incrementaba su complejidad. Este problema comenzó a
resolverse con la aparición de un traductor llamado ensamblador que convierte programas en ensamblador a
código máquina. Sin embargo, aunque el lenguaje ensamblador proporciona grandes facilidades, se
necesitaban herramientas mas potentes que manipularan la creciente complejidad de los programas.
Los lenguajes de alto nivel tales como FORTRAN, Basic, PASCAL y C. dieron un paso más hacia la
resolución de la complejidad inherente al software. El nacimiento de la programación estructurada, soportada
fundamentalmente por los lenguajes Pascal y C El uso de estos lenguajes estructurados junto con las técnicas
estructuradas facilitaron considerablemente la escritura de programas y disminuyeron la complejidad inherente
a los mismos.
Sin embargo. cuando un proyecto alcanza un cierto tamaño, su complejidad puede hacerlo incontrolable.
Además, hoy día el aumento de potencia de las características hardware y software, tales como elevada s
frecuencias de los procesadores, grandes capacidades de los discos duros, potencia de gráficos, facilidades
de conexión en redes, etc., incrementan la complejidad de los programas. Además de todo lo anterior, los
usuarios esperan interfaces gráficos basados en ventanas, acceso transparente a los datos almacenados en
computadoras mini o grandes y, naturalmente, la capacidad de trabajo en red. Para enfrentarse a esta
complejidad, los programadores de la década de los noventa utilizan la programación orientada a objetos
(POO)
POO es un nuevo medio de organizar código y datos que auguran un control creciente sobre la
complejidad del proceso de desarrollo del software.
Programación orientada a objetos (POO) no es una idea nueva; sus conceptos fundamentales ya existían
en lenguajes tales como Simula 67 y Smalltalk. Las propiedades fundamentales de la P0O son: objetos
(abstracción de datos), herencia y polimorfismo. Sin embargo, sí es nuevo el interés de los programadores, por
POO y por los lenguajes OO, especialmente C++.
Si usted es un programador experimentado de C, encontrará fácil aprender la sintaxis de C++. Caso de
tener conocimientos básicos de C o Pascal, la emigración a C++ le puede resultar un poco más ardua, pero de
cualquier forma, el esfuerzo suplementario estamos seguros le producirá grandes beneficios.
El mejor medio para aprender C + +, consideramos que es comprender bien los conceptos de POO y ver
como C++ los soporta. Este libro explica POO a través de ejemplos, a la vez enseña el lenguaje de
programación C++, y este capítulo explica en particular la terminología básica POO y los lenguajes de
programación orientados a objetos
LA EVOLUCIÓN DE LA PROGRAMACIÓN
POO (programación orientada a objetos) es un importante conjunto de técnicas que se pueden utilizar para
hacer el desarrollo de programas más eficiente mientras se mejora la fiabilidad de los programas resultantes.
En esencia, POO es un nuevo medio de enfocar el trabajo de programación. Sin embargo, a fin de
comprender lo que es POO, es necesario comprender sus raíces. Así pues, comencemos examinando la
historia del proceso de programación, analizando cómo evolucionó POO y deduciendo, en consecuencia, por
qué es tan importante este concepto.
Yatay 240 - Buenos Aires - República Argentina
27 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Programación lineal
La programación de computadoras es una joven disciplina. Las primeras computadoras se desarrollaron hace
cuarenta años. En estos cuarenta años la evolución de la programación ha sido enorme y se ha dirigido hacia
las necesidades del programador, es decir, se ha humanizado. En inglés, Object Oriented Programing (OOP).
Los primeros lenguajes de programación se diseñaron para desarrollar programas que realizaban tareas
relativamente simples. La mayoría de estos programas eran cortos, menos de 100 líneas de código fuente.
A medida que aumentaba la potencia de las computadoras, se requerían programas cada vez más
complejos. Los lenguajes de programación primitivos eran inadecuados para esas tareas de programación.
Los lenguajes de programación lineal (primeras versiones de Basic, COBOL y FORTRAN) no tenían facilidad
para reutilizar el código existente de programas. De hecho, se duplicaban segmentos de software cada vez
más en muchos programas. Los programas se ejecutaban en secuencias lógicas, haciendo su lógica difícil de
comprender. El control del programa era difícil y se producían continuos saltos a lo largo del referido programa.
Aún más, los lenguajes lineales no tenían capacidad de controlar la visibilidad de los elementos dato, Todos los
datos eran globales, por consiguiente podían ser modificados por cualquier parte del programa. No existían
datos locales y en consecuencia cualquier ligera modificación en un dato podía afectar a todo el programa.
La evolución de los lenguajes produjo la aparición de los lenguajes estructurados (Pascal, C, Ada ) así
como una nueva estructura, el procedimiento (subprograma o rutina) que consistía en secuencias de
instrucciones que realizaban una tarea determinada. Estos procedimientos tienen un nombre y suelen ser
realizados por un programador. Sin embargo, este nacimiento no supuso la solución a la resolución de
problemas complejos mediante programas, ya que se requerían numerosos procedimientos y prolijos sistemas
de comunicación entre ellos.
Programación modular
En principio, la solución a estos problemas era evidente: romper los programas grandes en componentes más
pequeños que pueden ser construidos independiente
Prog PpAL
MEDIA
SUBRUTINA
MEDlA
FIGURA 1-1. Una subrutina llamada desde dos posiciones.
Esta estrategia general se conoce como programación modular, y ha sido el paradigma que más éxito ha
tenido en la construcción de software.
El soporte más elemental para la programación llegó con la aparición de la subrutina al principio de la
década de los ochenta. una subrutina ha creado una secuencia de instrucciones a las que se les da un
nombre independiente; una vez que se ha definido, la subrutina se puede ejecutar simplemente incluyendo su
nombre en el programa siempre que se refiera. Las subrutinas proporciona una división natural (de la tarea
diferentes programadores escriben las diferentes subrutinas, y a continuación se ensamblan las subrutinas
terminadas en un único programa.
Aunque las subrutinas proporcionan el mecanismo básico de la programación modular, se necesita mucha
disciplina para crear software bien estructurado. Sin esta disciplina, es fácil escribir programas complicados y
tortuosos difíciles de modificar y comprender y casi imposibles de mantener. Esta ha sido la panorámica
durante muchos años en la industria del software.
Yatay 240 - Buenos Aires - República Argentina
28 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Programación estructurada
En la década de los sesenta y principio de los setenta, se produjo la primera gran revolución. la introducción de
la programación estructurada. Los programas estructurados se organizan de acuerdo a las operaciones que
ellos ejecutan. En esencia, el programa se (descompone en procedimientos individuales (también se conocen
como funciones) cada uno de los cuales se descompone en subprocedimientos hasta llegar al nivel de
procedimiento individual sencillo. Equipos de diversos programadores escriben los diferentes procedimientos
que se ensamblan posteriormente en el programa completo. La información se pasa entre procedimientos
utilizando parámetros y los procedimientos pueden tener datos locales a los que no se puede acceder desde
fuera del ámbito del procedimiento.
El objetivo final era hacer el (desarrollo de software más fácil para el programador mientras se mejoraba la
fiabilidad y mantenibilidad. Aislando los procesos dentro de funciones. un programa estructurado ni minimiza el
riesgo de que un procedimiento afecte a otro. Esto facilita también la detección de problemas mediante la
localización de errores, y hace el programa más claro.
Las variables globales desaparecen y se han sustituido por parámetros y variables locales que tienen un
ámbito controlable más pequeño.
Un concepto muy importante introdujo la programación estructurada: abstracción. La abstracción se puede
definir como la capacidad de examinar algo sin preocuparse de los detalles internos. En un programa
estructurado, es suficiente conocer que un procedimiento dado realiza una tarea específica. El cómo se realiza
la tarea no es importante; mientras el procedimiento sea fiable. Se puede utilizar sin tener que conocer como
funciona su interior. Esto se conoce como una abstracción funcional y es el núcleo de la programación
estructurada. Hoy casi todos los lenguajes de programación tienen construcciones que facilitan la
programación estructurada.
Una debilidad de la programación estructurada aparece cuando programadores diferentes trabajan en una
aplicación como un equipo. En un programa estructurado, a cada programador se le asigna la construcción de
un conjunto específico de funciones y tipos de datos. Dado que programadores diferentes manipulan funciones
separadas que pueden referirse a tipos de datos mutuamente compartidos, los cambios de un programador se
deben reflejar en el trabajo del resto del equipo. Los problemas de la comunicación entre los miembros del
equipo pueden producir graves errores. Otro problema serio de la programación estructurada es que
raramente es posible anticipar el diseño de un sistema completo antes de que se implemente realmente.
En esencia el defecto de la programación estructurada, como se acaba de ver, consiste en la separación
conceptual de datos y código. Este defecto se agrava a medida que el tamaño del programa se hace más
complejo
Abstracción de datos
La abstracción se define como la «extracción de la propiedades esenciales de un concepto». Con la
abstracción de datos, las estructuras de datos e ítems se pueden utilizar sin preocuparse sobre los detalles
exactos de la implementación. Por ejemplo, los números en coma flotante son abstracciones en todos los
lenguajes de programación; no tiene que preocuparse de la representación binaria exacta de un número en
coma flotante cuando se le asigna un valor. No se requiere conocer las complejidades de la multiplicación
binaria para multiplicar valores en coma flotante; lo más importante es que los números en coma flotante
funcionen de modo correcto.
La abstracción de datos permite no preocuparse de los detalles no esenciales. La abstracción de datos
existe en casi todos los lenguajes de programación. Las estructuras de datos y los tipos de datos son un
ejemplo de abstracción. Los procedimientos y las funciones son otro ejemplo. Sin embargo, sólo recientemente
han emergido lenguajes que soportan sus propios tipos abstractos de datos (TAD), como Pascal, Ada y
Modula-2. y naturalmente C ++.
Yatay 240 - Buenos Aires - República Argentina
29 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
¿QUE ES LA PROGRAMACION ORIENTADA A OBJETOS?
El término programación orientada a objetos (POO), hoy día ampliamente utilizado, es difícil de definir, ya que
no es un concepto nuevo sino que ha sido el desarrollo de técnicas de programación desde principios de la
década de los setenta. aunque sea en la década de los noventa cuando ha aumentado su difusión, uso y
popularidad. No obstante, se puede definir POO como una técnica o estilo de programación que utiliza objetos
como bloque esencial de construcción.
Los objetos son en realidad como los tipos abstractos de datos, ampliamente utilizados por los
programadores en la década de los setenta y ochenta. Un tipo abstracto de datos (TAD) es un tipo de dato
definido por el programador junto con un conjunto de operaciones que se pueden realizar sobre ellos. Se
denominan abstractos para diferenciarlos de los tipos de datos fundamentales o básicos definidos, por ejemplo
en C, tales como int, char y double. En C se puede definir un tipo abstracto de dato utilizando typedef y struct y
la implementación de las operaciones con un conjunto de funciones, C++ tiene muchas facilidades para definir
y utilizar tipo TAD. Al igual que los tipos de datos definidos por el usuario, un objeto es una colección de datos,
junto con las funciones asociadas, utilizadas para operar sobre esos datos. Sin embargo, la potencia real de
los objetos reside en las propiedades que soportan: herencia, encapsulamiento y polimorfismo junto con los
conceptos de objetos, clases, métodos y mensajes.
Trabajando con objetos
En programación convencional, los programas se dividen en dos componentes:
procedimientos y datos. Cada procedimiento actúa como una caja negra; es un componente que realiza una
tarea específica tal como convertir un conjunto de números o visualizar una ventana. Si las cajas negras se
dividen correctamente, se pueden escribir código para cada una sin preocuparse de lo que internamente hacen
otras cajas negras. La principal ventaja de utilizar este método es que ayuda a desarrollar programas que son
modulares y transportables.
Este método permite empaquetar código de programa en procedimientos. Pero ¿qué sucede con los
datos? Las estructuras de datos utilizadas en programas son, frecuentemente, globales o se pasan
explícitamente con parámetros. En esencia los datos, se tratan separadamente de los procedimientos.
Cuando se utilizan métodos de POO, un programa se divide en componentes que contienen
procedimientos y datos. Cada componente se considera un objeto.
Un objeto es una unidad que contiene datos y las funciones que operan sobre esos datos. A
elementos de un objeto se les conoce como miembros; las funciones que operan sobre los objetos
denominan métodos (en C++ los métodos se denominan también funciones miembro) y los datos
denominan miembros datos. En C++ un programa consta de objetos. Los objetos de un programa
comunican entre sí mediante el paso o envío de mensajes (acciones que debe ejecutar el objeto).
¿Qué son objetos en POO? La respuesta es cualquier entidad del mundo real que se pueda imaginar:
• Objetos físicos
Automóviles en una simulación de tráfico.
Aviones en un sistema de control de tráfico aéreo.
Componentes electrónicos en un programa de diseño de circuitos.
Animales mamíferos.
• Elementos de interfaces gráficos de usuarios
Ventanas.
Iconos.
Menús.
Objetos gráficos (líneas, rectángulos, círculos).
Ratones.
Teclados.
Yatay 240 - Buenos Aires - República Argentina
30 de 76
V 5.0.0
los
se
se
se
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
• Estructuras de datos
Arrays.
Pilas.
Colas.
Árboles binarios.
• Tipos de datos definidos por el usuario
Números complejos.
Hora del día.
Puntos de un plano
.
Examinaremos un ejemplo para ver como POO actúa de modo diferente a la programación convencional.
Supongamos que se dispone de un objeto tal como una ventana en la pantalla, y se desea definir las cuatro
operaciones requeridas para mover el objeto ventana en la pantalla:
1.
2.
3.
4.
Mover el objeto ventana a la derecha.
Mover el objeto ventana a la izquierda.
Mover el objeto ventana hacia arriba.
Mover el objeto ventana hacia abajo.
Utilizando métodos de programación convencional, se puede escribir un procedimiento independiente para
cada operación. Estos procedimientos actúan como cajas negras y suponen un mecanismo idóneo para dividir
operaciones. Desgraciadamente, los datos que definen el objeto son independientes de cada uno de los
procedimientos.
Examinaremos ahora el método para definir el objeto visual utilizando métodos orientados a objetos.
Aplicando este método combinamos datos y procedimientos en un único paquete. Para ello, el primer paso es
crear un objeto llamado ventana. Esta ventana, contiene los procedimientos que definen cómo se mueve la
ventana. Cuando la ventana recibe una orden tal como mover a izquierda se ejecuta el procedimiento
correspondiente.
Los objetos soportan una serie de características específicas de los mismos:
• Se agrupan en tipos denominados clases.
• Contienen datos internos que definen su estado actual.
• Soportan ocultación de datos.
• Pueden heredar propiedades de otros objetos.
• Pueden comunicarse con otros objetos enviando o pasando mensajes.
• Tienen métodos que definen su comportamiento.
Definición de objetos
Un objeto es una unidad que contiene datos y las funciones que operan sobre esos datos. Los datos se
denominan miembros dato y las funciones, miembros función (también funciones miembro) o métodos.
Los datos y las funciones se encapsulan en una única entidad. Los datos están ocultos y solo mediante las
funciones miembro es posible acceder a ellos. Los términos encapsulación (encapsulamiento) de datos y
ocultación de datos son términos claves empleados en los lenguajes de programación.
Un método gráfico para representar los objetos se representa en la Figura 1.4. Un objeto se representa con
un cuadro. El cuadro se etiqueta con el nombre del objeto. El cuadro (perímetro del mismo) representa el límite
o frontera entre el interior y el exterior de un objeto. En el interior de un objeto están las variables locales —los
campos miembro— y las funciones. Un campo se representa por un cuadro rectangular, una función por un
hexágono, Los campos y las funciones se rotulan con sus nombres. Todos los campos miembros y las
funciones que están completamente en el interior del cuadro objeto son ocultos desde el exterior, lo que
significa que estas características están encapsuladas. Los campos o funciones que se extienden fuera del
cuadro son accesibles, desde el exterior y actúan de interfaz. El acceso a las características miembro (campos
y funciones) es posible a través del interfaz del objeto.
Yatay 240 - Buenos Aires - República Argentina
31 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Objeto
MIEMBROS DATOS
MÉTODOS
(Funciones
miembro)
I
N
T
E
R
F
A
Z
MIEMBROS FUNCIÓN
VARIABLES
Miembros Dato
FIGURA 1-4. Diagrama de un objeto.
Un programa, típicamente, consta de un número de objetos que se comunican entre si mediante métodos
que son, a su vez, llamadas funciones miembro del objeto invocado. La organización de un programa en C++
se muestra en la Figura 1-5.
En C ++ las funciones se denominan funciones miembro y en otros lenguajes orientados a objetos (LOO) tales como Smalltalk- métodos.
Clases
En POO se suele decir que los objetos son miembro de clases. Una clase es un tipo definido por el usuario que determina
las estructuras de datos y las operaciones asociadas con ese tipo.
Datos
objeto
Función
miembro
Datos
Función
miembro
Función
miembro
objeto
Datos
Función
miembro
Función
miembro
objeto
FIGURA 1-5 Programa orientado a objetos.
Función
miembro
Las clases son como plantillas o modelos que describen como se construyen ciertos tipos de objetos. Cada
vez que se construye un objeto de una clase, se crea una instancia (instance) de esa clase. Por consiguiente,
los objetos son instancias de clases. En general, los términos objetos e instancias de una clase se pueden
utilizar indistintamente. Una clase es una colección de objetos similares y un objeto es una instancia de una
definición de una clase. Una clase puede tener muchas instancias y cada una es un objeto independiente.
Una clase es simplemente un modelo que se utiliza para describir uno más objetos del mismo tipo.
Así, por ejemplo, sea una clase ventana, un tipo de dato, que contenga los miembros dato:
posx, posy
tipo ventana
tipo borde
color ventana
y unas funciones miembro:
mover_horizontal
mover_vertical
Un objeto de la clase ventana es una ventana concreta —una instancia de la clase— cuyos datos tienen
por valores x, y; desplegable; línea doble, amarillo.
Desplegable
x,y
amarillo
doble línea
Yatay 240 - Buenos Aires - República Argentina
32 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
FIGURA 1-6. Relación entre una clase ventana y un objeto ventana.
FIGURA 1-7. Construcción de botones en entornos de ventanas (Windows).
La comunicación con el objeto se realiza a través del paso de mensajes. El envío de un mensaje a una
instancia de una clase produce la ejecución de un método (función miembro en C ++). El paso de mensajes es
el termino utilizado para referirnos a la invocación o llamada de una función miembro de un objeto. La noción
de paso de mensajes es fundamental en todos los lenguajes de programación orientada a objetos.
Algunos ejemplos típicos de clases en los interfaces gráficos de usuarios. son los populares botones de las
populares interfaces Windows, o X—Windows.
Mensajes: activación de objetos
A diferencia de los métodos tradicionales, cuyos elementos datos son pasivos, los objetos pueden ser
activados mediante la recepción de mensajes. Un mensaje es simplemente una petición de un objeto a otro
objeto para que éste se comporte de una determinada manera, ejecutando uno de sus métodos. La técnica de
enviar mensajes se conoce como paso de mensajes. La figura 1-8 representa un objeto A (emisor) que envía
un mensaje TEST al objeto B (receptor).
Mensaje test
Objeto A
objeto emisor
Objeto B
y objeto receptor
Resultados( de la ejecución del método test)
FIGURA 1-8. Paso de mensajes entre objetos.
Estructuralmente, un mensaje consta de tres partes: la identidad del objeto receptor, el método (función
miembro) del receptor que va ejecución se ha solicitado y cualquier otra información adicional que el receptor
pueda necesitar para ejecutar el método requerido. Esta información suele darse en forma de parámetros. Por
ejemplo, una posible sintaxis de mensaje podría ser
“T1 Imprimir Hola Mundo”
receptor
método
parámetros
En el caso de C++ la notación utilizada es
nombre del objeto . función _ miembro o método ( parámetros )
Yatay 240 - Buenos Aires - República Argentina
33 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Así, en el caso de un objeto T1 (miembros dato: nombre de un alumno y curso en que está matriculado;
miembros función: LeerNombre, obtiene el nombre del alumno e Imprimir, visualiza el citado nombre), que
recibe un mensaje Imprimir, se expresara así:
T1
Nombre
objeto
Curso
Leer nombre
Imprimir
___
Imprimir( )
T1. Imprimir ( )
sin parámetros
mensaje
FIGURA 1-9. Envío del mensaje Imprimir.
La sentencia anterior se lee del siguiente modo: «enviar el mensaje imprimir al objeto T1. El objeto T1
reacciona al mensaje ejecutando la función miembro (método) de igual nombre que el mensaje. Si el mensaje
Imprimir visualizara el nombre de una persona, éste se visualizaría en el dispositivo de salida.
Como se ha comentado anteriormente el mensaje podía llevar parámetros. Así, en el caso de enviar el
mensaje LeerNombre consideremos la invocación de: T1.LeerNombre(“Luis Mackoy Flanagan”)
Esta sentencia representa el envío del mensaje LeerNombre al objeto T1con el argumento “Luis Mackoy
Flanagan”. El objeto T1 es el receptor del mensaje y —como respuesta al mismo— ejecuta su función miembro
LeerNombre con el parámetro pasado.
Los mensajes juegan un papel vital en POO; sin ellos, los objetos que se definan no se podrán comunicar
con otros objetos. Desde un punto de vista convencional, el paso de mensajes no es más que el sinónimo de
llamada a una función. De hecho, esto es lo que sucede cuando un mensaje se envía a un programa C++.
Programa orientado a objetos
Un programa orientado a objetos es una colección de clases. Necesitará una función principal que cree objetos
y comience la ejecución mediante la invocación de sus funciones miembro o métodos.
Esta organización conduce a separar partes diferentes de una aplicación en distintos archivos. La idea
consiste en poner la descripción de la clase para cada una de ellas en un archivo separado. La función
principal también se pone en un archivo independiente. El compilador ensamblará, entonces, el programa
completo a partir de los archivos independientes en una única unidad. Naturalmente, las clases que están en
archivos independientes en una única unidad. Naturalmente, las clases que están en archivos independientes
se pueden utilizar en más de una aplicación.
En realidad, cuando se ejecuta un programa orientado a objetos, ocurren tres acciones o sucesos.
En primer lugar, se crean los objetos cuando se necesitan (el mecanismo para creación de objetos se
explicará mas adelante). Segundo, los mensajes se envían desde unos objetos y se reciben en otros, a
medida que el programa procesa internamente información o responde a la entrada del usuario, Por
último, se borran los objetos cuando ya no son necesarios y se recupera la memoria ocupada por ellos.
Yatay 240 - Buenos Aires - República Argentina
34 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Herencia
Una característica muy importante de los objetos y las clases es la herencia. La herencia es la propiedad que
permite a los objetos construirse a partir de otros objetos. El concepto de herencia está presente en nuestras
vidas diarias donde las clases se dividen en subclases, Así por ejemplo, las clases de animales se dividen en
mamíferos, anfibios, insectos, pájaros, etc. La clase de vehículos se divide en automóviles (coches o carros),
autobuses, camiones y motocicletas.
El principio de este tipo de división es que cada subclase comparte características comunes con la clase de
la que se deriva. Los automóviles, camiones, autobuses y motocicletas —que pertenecen a la clase vehículo—
tienen ruedas y un motor; son las características de vehículos. Además de las características compartidas con
otros miembros de la clase, cada subclase tiene sus propias características particulares: autobuses, por
ejemplo, tienen un gran número de asientos, un aparato de televisión para los viajeros, mientras que las
motocicletas tienen dos ruedas, un manillar y un asiento doble.
La idea de herencia se muestra en la Figura 1-10. Observen en la figura que las características A y B que
pertenecen a la clase base, también son comunes a
Característica A
Característica B
Clase
Característica A
Característica B
Característica C
base
Característica A
Característica B
Característica D
Característica A
Característica B
Característica E
Clases derivadas
FIGURA 1-10. Herencia.
Todas las clases derivadas, y a su vez estas clases derivadas tienen sus propias características.
De modo similar en POO, una clase se puede dividir en subclases. En C++ la clase original se denomina
clase base; las clases que se definen a partir de la clase base, compartiendo sus características y añadiendo
otras nuevas, se denominan clases derivadas.
Las clases derivadas pueden heredar código y datos de su clase base añadiendo su propio código especial
y datos a la misma.
La herencia permite definir nuevas clases a partir de clases ya existentes.
Por ejemplo, si se define tina clase denominada figura geométrica A se pueden definir las subclases o
clases derivadas cuadrado, circulo, rectángulo y triángulo.
La clase figura geométrica posee una función miembro calcular _ superficie que proporciona el valor cero.
La clase cuadrado posee el atributo lado y redefine la función calcular _ superficie() que proporciona el valor
“Lado * Lado” - La clase circulo posee el atributo radio y redefine la función calcular_superficie ( ) que
proporciona el valor radio * radio * pi (Figura 1-11).
La herencia impone una relación jerárquica entre clases en la cual una clase hija hereda de su clase padre.
Si una clase sólo puede recibir características de otra clase base, la herencia se denomina herencia simple. Si
una clase recibe propiedades de más de una clase base, la herencia se denomina herencia múltiple. Muchos
lenguajes orientados a objetos no soportan herencia múltiple, sin embargo C++ si incorpora esta propiedad.
Yatay 240 - Buenos Aires - República Argentina
35 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Polimorfismo
En un sentido literal, polimorfismo significa la cualidad de tener más de una forma. En el contexto de POO, el
polimorfismo se refiere al hecho que una misma operación puede tener diferente comportamiento en diferentes
objetos.
En otras palabras, diferentes objetos reaccionan al mismo mensaje de modo diferente. Por ejemplo,
consideremos la operación sumar. En un lenguaje de programación el operador + representa la suma de dos
números (x+y) de diferentes tipos: enteros, coma flotante Además se puede definir la operación de sumar dos
cadenas: concatenación, mediante el operador suma.
De modo similar, supongamos un numero de figuras geométricas que responden todas al mensaje, dibujar.
Cada objeto reacciona a este mensaje visualizando su figura en una pantalla de visualización. Obviamente, el
mecanismo real para visualizar los objetos difiere de una figura a otra, pero todas las figuras realizan esta
tarea en respuesta al mismo mensaje.
Figura geométrica
Calcular _ superficie
calcular superficie
se recibe de la clase base por
herencia
Cuadrado
(calcular _ superficie)
Lado m
Circulo
(calcular_ superficie)
radio r
Rectángulo
(calcular_superficie)
lados x,y
Triángulo
(calcular _superficie)
base y altura
FIGURA 1-11. clases: base y derivadas,
Reutilización
Una vez que una clase se ha escrito, creado, depurado y utilizado, se puede difundir entre otros
programadores para que puedan utilizarla en sus propios programas. Esta propiedad se denomina reutilización
o reutilizabilidad. – Es similar a la forma en que una biblioteca de funciones de un lenguaje procedimental se
puede incorporar en programas diferentes. En POO, el concepto de herencia proporciona tina importante extensión a la idea de la reutilizabilidad. Un
programador puede tomar una clase existente, y sin modificarla, añadir características y posibilidades
adicionales a la misma. Estas operaciones se realizan por derivación de una clase nueva a partir de una clase
existente. La nueva clase heredará las propiedades de la antigua, pero es posible añadir nuevas
características propias.
La reutilización del software es un término muy importante, que Cox ha definido con el concepto chip de
software (IC—Software), queriendo significar que esta propiedad es similar a la reutilización de hardware
mediante circuitos integrados. Los objetos en POO son fácilmente reutilizables y es una de las razones
principales para justificar la utilización de la metodología orientada a objetos en la mayoría de los casos. .Por
esta razón, cualquier aplicación POO suele venir con un conjunto de clases predefinido, que permitirá ahorrar
tiempo y esfuerzos en el desarrollo de las aplicaciones. Por esta razón, el número de clases predefinidas es
uno de los parámetros que se emplean para la evaluación y comparación de los distintos sistemas, aunque las
clases acompañantes no siempre serán exactamente equivalentes.
Yatay 240 - Buenos Aires - República Argentina
36 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
UNIDAD 4 Conceptos de Clases y Objetos
Una clase es una implementación de un tipo abstracto de datos TAD.
datos
atributos
•
•
•
•
•
•
+
+
operaciones TAD
métodos
Clase
Las clases, como los TAD, son declaraciones.
Instancias (lo que existe durante la ejecución) son: variables para un TAD, objetos para una clase.
Los datos se identifican como atributos en la clase: cada ejemplar (objeto) de la clase tendrá sus
propios atributos.
Todos los objetos de una clase tienen definido un mismo conjunto de métodos (operaciones).
Encapsulamiento de código y datos: se ve a la clase como módulo.
Ocultación de información: con partes pública/privada.
Las Clases En C++
Sintácticamente la definición de una clase es similar a struct
class Uno{
// Por defecto el contenido es private
Área Privada
No es visible desde el
exterior
private:
int _dato;
public:
Área Pública (servicios)
Visible desde el
exterior
void setDato(int dato);
int getDato();
void mostrar();
};
Siempre
termina en
punto y coma
Atributos y métodos
Los atributos deben estar ocultos (ser privados).
(si bien C++ permite declarar atributos públicos, pero lo correcto es que los atributos sean privados)
Los métodos se implementan con funciones miembro. La forma de las funciones (cabeceras de los métodos
públicos) debe ser visible desde el exterior (ser pública) y constituyen la interfaz de la clase.
Puede haber métodos privados (auxiliares para la clase, pero no identificados como métodos que ofrecen sus
servicios).
•
La Interfaz (lo público) son: los servicios (métodos públicos) que ofrece.
•
La Implementación (lo privado) son :los atributos, declaración de métodos privados y código de todos
los métodos (públicos y privados).
Yatay 240 - Buenos Aires - República Argentina
37 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Hay dos formas de desarrollar los métodos de una clase
1. Implementación de los métodos fuera de la estructura class
Los métodos pueden estar implementados fuera de la estructura class
(Es lo más correcto sobre todo si contiene más de 2 o 3 instrucciones):
Ejemplo del método mostrar( )
1
2
3
4
tipo Nombre de la clase Operador de resolución de ámbito (::) Nombre del método
5
parámetros
void Uno :: mostrar( ){
cout << "El dato es: " << _dato << endl;
}
Muestra el contenido del atributo _dato
2. Métodos (Funciones miembro) insertados
La implementación de los métodos puede también estar en la propia estructura class en forma de métodos
insertados.
class Uno {
private:
int _dato;
public:
void setDato(int dato) { _dato = dato; }
int getDato( ) { return _dato; }
No terminan en
punto y coma
void mostrar();
};
Forma general de un método implementado en forma de método insertado:
inline tipo nombre(parámetros) { código }
El método irá dentro de la estructura class y los parámetros son opcionales (y no figura tipo en los
constructores y destructores, como veremos más adelante).
La palabra clave inline se puede omitir (nosotros la omitiremos).
En el código de los métodos se puede usar todo lo que está declarado en la clase: lo público y también lo
privado. Por ejemplo, en el método mostrar( ) se puede usar lo siguiente:
atributo dato (privado), método “seteador” setdato (público) y método “geteador” getdato (público).
Creación y uso de objetos
La clase ya está terminada (declarada e implementada).Ya podemos crear objetos y trabajar con ellos:
void main(){
Objetos o instancias de la clase
Uno objeto1, objeto2;
objeto1.setDato(13);
objeto2.setDato(5);
objeto1.mostrar();
objeto2.mostrar();
cout << objeto1.getDato();
// 1º suceso
}
// 3º suceso
Pasaje de mensajes: NombreDelObjeto.Metodo(param)
// 2º suceso
Observe que tanto, Objeto1 como Objeto2, aceptan el mismo mensaje, pero cada uno tiene su propio juego de atributos
dato.
Yatay 240 - Buenos Aires - República Argentina
38 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Paso de mensajes
Los objetos se manipulan mediante el paso de mensajes.
Cada objeto entiende tantos mensajes como métodos públicos están definidos en su clase.
Paso de mensaje:
objeto receptor • método publico( argumentos)
El paso de mensaje provoca la ejecución del método con igual nombre que esté definido en la clase del objeto.
Cualquier objeto de la clase Uno entiende tres mensajes diferentes:
getDato( )
setDato( int dato )
mostrar( )
Visibilidad
Público y Privado
•
•
•
•
Los atributos deben ser privados. (Podrían existir métodos privados también)
Los métodos (métodos públicos) son accesibles por el objeto.
A través de los objetos de una clase sólo se puede acceder (con el operador •) a lo que esté declarado
como público en la clase.
Lo privado sólo puede ser accedido directamente desde dentro de la clase, en el código de los
métodos.
dato
setDato(int)
getDato()
mostrar()
Yatay 240 - Buenos Aires - República Argentina
Protegido
frente a
accesos
desde el
exterior
Accesible
desde el
interior
39 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
La clase (dentro del objeto)
•
•
•
•
•
•
Se conocen los atributos.
Se conocen todos los métodos (públicos o privados).
Implementa los métodos(públicos o privados):insertar
En el método se trabaja sobre o con el objeto receptor.
Para pasar otro mensaje al objeto receptor basta invocar el correspondiente método
(sin poner ni receptor ni punto).
El método puede utilizar también objetos locales (composición) y objetos parámetros.
Desde fuera del objeto
•
•
•
•
•
No se conocen sus atributos.
No se conocen sus métodos privados.
Sólo se conocen los servicios que proporciona (métodos públicos).
Se lo utiliza pasándole mensajes.
Paso de mensaje:
objeto.Mensaje
•
Se ejecuta el código del método con igual nombre que esté definido en su clase
(y con parámetros que concuerden).
Categoría de los métodos
En las clases se pueden identificar distintas categorías de métodos:
•
•
•
•
•
•
Métodos inicializadores: inicializan atributos.
Métodos geteadores: devuelven el contenido de los atributos. Ejemplo. getDato( ).
Métodos seteadores: establecen el contenido de los atributos
(cambian el contenido de un atributo). Ejemplo setDato(int).
Métodos visualizadores: muestran el objeto( valores de los atributos ) Ejemplo verTodo()
Métodos computadores: realizan cálculos y generan resultados(pueden o no devolver valores)
Otras categorías.
Yatay 240 - Buenos Aires - República Argentina
40 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Ejemplo: La clase Punto
class Punto {
private:
float _x;
float _y;
2 Atributos (Privados)
public:
void inicializa() { _x = 0; _y = 0;} Metodo Inicializador
void setx(float x) { _x = x; }
Metodo Seteador
void sety(float y) { _y = y; }
float getx () { return _x; }
Método geteador
float gety() { return _y; }
void verTodo();
Método visualizador
}; Finaliza con Punto y coma
void Punto::verTodo(){
cout<<”x vale:”<< _x <<” y vale:”<< _y <<endl ;
} No Finaliza con Punto y coma
Convención de denominaciones
Para dar nombre a los elementos de los programas se puede utilizar cualquier convenio de denominación,
pero lo mejor es utilizar uno y ser consecuente. Aquí vamos a seguir las siguientes reglas:
Los identificadores se escribirán en general en minúsculas, A excepción, en los casos que se indique, de
ciertas letras.
•
Las nombres de clases comenzarán por mayúscula: Clase, Punto, Circulo.
•
Los atributos comenzaran con el carácter _ ejemplo: int _codigo;
•
Los métodos comenzarán por minúscula: mostrar( ), dato( ).
•
Lo objetos comenzarán por minúscula: objeto1, punto.
•
El nombre de un método geteador comenzara con la palabra get ejemplo: getDato( ), getX( ); el
método devolverá el valor del atributo.
•
El nombre de un método seteador comenzara con la palabra set ejemplo: void setDato( int dato),
void setX( float x); el método modificara el valor del atributo.
•
Los parámetros que modificaran los atributos tendrán el mismo tipo y nombre del atributo sin el
carácter _ ejemplo: void setDato( int dato)
•
identificadores compuestos por varias palabras: la segunda y siguientes palabras llevarán su primera
letra en mayúscula: listaObjetosGraficos, circuloColor.
Yatay 240 - Buenos Aires - República Argentina
41 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Representación gráfica
Para representar gráficamente los elementos de los POO vamos utilizar diagramas similares a los de UML
Representación de las Clases
Nombre
Atributos
Nombre de la Clase
Atributos definidos en
la clase
Métodos
Métodos definidos en
la clase
Representa…
Responsabilidad de la
clase
Las representaciones graficas se pueden desarrollar con distintos niveles de detalle. En el mayor se
incluyen todas las características (atributos y métodos) definidas en la clase y la responsabilidad de
la clase(que representa)
Punto
_x
_y
setX (int)
getX():int
setY(int)
getY():int
verTodo()
Métodos:
Nombres seguido de los tipos
de los parámetros separados
por comas y entre paréntesis.
Si la función devuelve un
valor, el tipo se coloca al final
precedido de :
Representa un punto en
el plano
Yatay 240 - Buenos Aires - República Argentina
42 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Ejemplo de una clase Cuenta (bancaria)
Una clase para cuentas de un banco
Vamos a modelar con una clase objetos que representen cuentas de un banco. La información (atributos) de
tales objetos será básica: el número de la cuenta, el saldo y el interés anual. Como en algún momento vamos
a querer mostrar información en la pantalla, lo primero es incluir la biblioteca iostream.h:
#include <iostream.h> // entrada/salida por consola de c++
Ahora nos centramos en la clase a desarrollar
Lo primero es elegir un nombre para la clase: Cuenta
#include <iostream.h>
class Cuenta {
El nombre de la clase comienza con mayúsculas
};
Ahora, nos centramos en los atributos, la información que han de contener los objetos de la clase Cuenta.
Establecemos un nombre y una forma (tipo) para cada atributo.
Colocamos la descripción de los atributos en la parte privada:
#include <iostream.h> // entrada/salida por consola
class Cuenta {
private:
long int _numero; // número de cuenta
float _saldo;
// saldo actual
float _interes; // interés anual (porcentaje)
};
El nombre de los atributos comienza por subrayado y va en minúsculas
A continuación nos preguntamos si resulta adecuado un método que se encargue de la inicialización de los
objetos de las clase Cuenta.
En este caso sí resultará adecuado tal método, pero concluimos que no debe servir para inicializar el atributo
_numero, sino más bien que ese dato se proporcione al inicializar y ya no se cambie:
#include <iostream.h> // entrada/salida por consola
class Cuenta {
private:
long int _numero; // número de cuenta
float
_saldo; // saldo
float
_interes; // interés anual (porcentaje)
public:
void inicializa(long int numero) {_numero = numero; _saldo = 0; _interes = 0;}
};
El nombre de los métodos en minúsculas
Yatay 240 - Buenos Aires - República Argentina
43 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
A continuación nos preguntamos si resulta adecuado que haya métodos seteadores y geteadores para cada
atributo. Nos parecen adecuados para _saldo e _interes, pero no para numero:
#include <iostream.h> // entrada/salida por consola
class Cuenta {
private:
long int _numero; // número de cuenta
float _saldo;
float _interes; // interés anual (porcentaje)
public:
void inicializa(long int numero){_numero=numero;_saldo = 0; _interes = 0;}
float getSaldo() { return _saldo; }
float getInteres() { return _interes; }
void setSaldo(float saldo) { _saldo = saldo; }
void setInteres(float interes) { _interes = interes; }
};
Luego nos preguntamos por el resto de los métodos que deben proporcionar los objetos de la clase y los
incluimos como métodos:
#include <iostream.h> // entrada/salida por consola
class Cuenta {
private:
long int _numero; // número de cuenta
float _saldo;
float _interes; // interés anual (porcentaje)
public:
void inicializa(long int numero){_numero = numero;_saldo =0;_interes = 0;}
float getsaldo() { return _saldo; }
float getinteres() { return _interes; }
void setsaldo(float saldo) { _saldo = saldo; }
void setinteres(float interes) { _interes = interes; }
void deposito(float cantidad) { _saldo += cantidad; }
bool extraccion(float cantidad);
void abonoIntereses();
void mostrar();
};
Los métodos sencillos (una instrucción de código) los hemos implementado directamente en la estructura
class (insertados); los demás métodos los implementamos:
bool Cuenta::extraccion(float cantidad) {
// devuelve true si hay saldo suficiente (y resta la cantidad)
// false si no hay saldo suficiente
if(cantidad > _saldo) return false;
_saldo -= cantidad;
return true;
}
void Cuenta::abonoIntereses() {
// abono mensual de intereses
deposito(saldo * interes / 100 / 12);
// el objeto se pasa un mensaje a sí mismo(deposito)cuando no figura delante del
// mismo, ningún objeto receptor del mensaje, éste se envía a uno mismo
}
void Cuenta::mostrar() {
cout << endl;
cout << "Número de cuenta: " << numero << endl;
cout << "Saldo: " << saldo << endl;
}
Yatay 240 - Buenos Aires - República Argentina
44 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Para usar la clase basta conocer su nombre y la forma de sus métodos
Cuenta
inicializa(long int)
setSaldo(float)
getSaldo():float
interes():float
deposito(float)
extraccion(float)
abonoIntereses()
mostrar()
Uso de la Clase Cuenta
void main(){
Cuenta cc;
cc.inicializa(24316534);
cc.saldo(100000);
cc.interes(10);
cc.mostrar();
cc.deposito(26000);
cc.mostrar();
cc.abonoIntereses();
cc.mostrar();
if (! cc.extraccion(10000))
cout << "No hay saldo";
cc.mostrar();
Número de cuenta: 24316534
Saldo: 100000
Número de cuenta: 24316534
Saldo: 126000
Número de cuenta: 24316534
Saldo: 127050
Número de cuenta: 24316534
Saldo: 117050
}
Yatay 240 - Buenos Aires - República Argentina
45 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Que ocurre durante la ejecución
Diagramas para el análisis de la ejecución de los programas
Para el análisis de las ejecuciones de los programas utilizaremos otro tipo de diagrama para representar los
objetos y ver cómo varía su estado a lo largo de la ejecución.
Cada objeto se representará como una caja identificada con el nombre del objeto en cuestión:
Objeto cc
Atributos
Numero
Saldo
Interes
void Cuenta::mostrar(){
cout << endl;
cout << "La cuenta: " << _numero ;
cout << "tiene un saldo de: " << _saldo << endl;
}
void main(){
Cuenta cc;
cc.inicializa(24316534);
cc.setSaldo(100000);
cc.setinteres(10);
cc.mostrar( );
}
cc
Cuenta = ?
Saldo = ?
Intereses = ?
1- La aplicación crea un objeto cc, con sus métodos y sus tres atributos.
Los atributos tienen valores desconocidos.
cc
Cuenta = 24316534
2- El objeto aplicación envía el mensaje inicializa(24316534) al objeto cc.
Se inicializan los atributos. En este caso el atributo nro de cuenta
recibe el valor por parámetro.
Saldo = 0
Intereses = 0
3- El objeto aplicación envía el mensaje saldo(100000) al objeto cc.
Se modifica el atributo saldo.
cc
Cuenta = 24316534
Saldo = 100000
Intereses = 0
Yatay 240 - Buenos Aires - República Argentina
46 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
4- El objeto aplicación envía el mensaje interes(10) al objeto cc. Se modifica el atributo interes.
cc
Cuenta = 24316534
Saldo = 100000
Intereses = 10
5- El objeto aplicación envía el mensaje mostrar( ) al objeto cc.
Se ejecuta el método mostrar( ) de la clase Cuenta sobre el objeto cc, mostrándose en la pantalla, entre
otras cosas, los valores de los atributos numero y saldo de ese objeto cc.
La cuenta 24316534 tiene un saldo de 100000
Yatay 240 - Buenos Aires - República Argentina
47 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Ejemplos De funciones con Parámetros con valores por defecto en C++
// ejemplo de parámetros por defecto
#include<iostream.h>
#include<conio.h>
void param(int i=0, char r='a', float f=21);
void main(){
param(1,'x',99.99);
param(1,'x');
param(1);
param();
}
//
//
//
//
//
//
llamada con 3 parámetros
llamada con 2 parámetros
el tercero toma el valor 21
llamada con 1 parámetro
el 2 toma el valor ’a’ y el 3 el valor 21
sin parámetros los valores son i=0, r='a', f=21
void param(int i, char r, float f){
// acá va el código
...
}
Ejemplos sobrecarga de funciones en C++
// Ejemplo de sobrecarga de funciones en c++
#include<iostream.h>
#include<conio.h>
// las 3 funciones se llaman igual tienen distintos tipos de
// parámetros pero tienen igual cantidad de los mismos
int alcuadrado(int i);
float alcuadrado(float f);
double alcuadrado(double d);
int alcuadrado(int i){
return i*i;
}
float alcuadrado(float f){
return f*f;
}
double alcuadrado(double d){
return d*d;
}
void main(){
int a=10;float f=2.2;double d=100.1;
// según el tipo que recibe elige la función a ejecutar
clrscr();
cout<<"el cuadrado de"<<a<<" es:"<<alcuadrado(a)<<endl;
cout<<"el cuadrado de"<<f<<" es:"<<alcuadrado(f)<<endl;
cout<<"el cuadrado de"<<d<<" es:"<<alcuadrado(d)<<endl;
}
Yatay 240 - Buenos Aires - República Argentina
48 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Ejemplos de punteros de estructuras y punteros de objetos en C++
// ejemplo de punteros de estructuras y punteros de objetos en c++
#include<iostream.h>
#include<conio.h>
#include<string.h>
// defino una estructura todos los componentes son públicos
struct rec{
int cod;
char nom[20];
};
class base {
int c;
public:
int verc();
void setc(int i);
};
int base::verc(){
return c;
}
void base::setc(int i){
c=i;
}
void main(){
base b;
// instancia objeto clase base
base *pb;
// un puntero de clase base
pb=&b;
// le asigna una dirección
//pb= new base;
o pide memoria
struct rec r;
// declaro una variable del tipo struct rec
struct rec *pr;
// declaro un puntero del tipo rec
r.cod=10;
strcpy(r.nom,"pepe");
pr=&r;
// le asigno una dirección valida
pr->cod=10;
strcpy(pr->nom,"pepe");
base *ppb=new base;
clrscr();
b.setc(10);
cout<<"el valor de
pb->setc(0);
cout<<"el valor de
ppb->setc(190);
cout<<"el valor de
delete ppb;
}
// pido memoria
c es"<< b.verc();
c es"<< pb->verc();
c en ppb es"<< ppb->verc();
// libero memoria
// visibilidad de datos miembro y métodos en las clases
Parte de la Clase
Public
Protected
Private
accesible desde
propia clase
Si
Si
Si
Yatay 240 - Buenos Aires - República Argentina
accesible desde
si
si
no
49 de 76
clase derivada
accesible
objetos
si
no
no
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Ejemplos de funciones virtuales en C++
// ejemplo de funciones virtuales en c++
#include<iostream.h>
#include<conio.h>
#include<string.h>
class base {
public:
void mostrar(){cout <<"estoy en base"<<endl;}
virtual void mostrar2(){cout <<"estoy en base"<<endl;}
};
class derivada: public base{
public:
void mostrar(){ cout<<"estoy en derivada"<< endl;}
virtual void mostrar2(){cout <<"estoy en derivada"<<endl;}
};
void main(){
base b;
// instancia objeto clase base
derivada d;
// instancia objeto clase derivada
base *pb;
clrscr();
pb=&d;
pb->mostrar(); // ignora el contenido del puntero
pb->mostrar2(); //se basa en el contenido del puntero
}
Yatay 240 - Buenos Aires - República Argentina
50 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
// ejemplo de funciones virtuales puras
#include<iostream.h>
#include<conio.h>
class base {
public:
virtual void mostrar()=0; //
};
class cuad: public base{
public:
void mostrar(){ cout<<"estoy
};
class tria: public base{
public:
void mostrar(){ cout<<"estoy
};
class circ: public base{
public:
void mostrar(){ cout<<"estoy
};
es una clase abstracta
en cuadrado"<< endl;}
en triangulo"<< endl;}
en circulo"<< endl;}
Nota: Cuando una Clase contiene al menos una función miembro = a 0, la clase se transforma en Clase
Abstracta. Una Clase Abstracta no puede ser instanciada y para crear un objeto de esta se debe crear una
clase derivada y escribir el código de la función miembro que es virtual pura. Ejemplos:
Main(){
....
base objeto_base ;
// Provoca un error de compilacion
....
}
class no_funciona: public base {
void otra_funcion();// Provoca un error de compilacion, porque falta el código de mostrar
}
Main(){
....
no_funciona objeto_base ;....
}
void main(){
cuad c;
// instancia objeto clase base
tria t;
// instancia objeto clase derivada
circ ci;
base *pb[3];
int i;
base b; // no compila por ser clase abstracta y no se permite instanciar
clrscr();
pb[0]=&c; //le asigna un puntero de clase derivada a uno de clase base
pb[1]=&t; //le asigna un puntero de clase derivada a uno de clase base
pb[2]=&ci; //le asigna un puntero de clase derivada a uno de clase base
for (i=0; i<3;i++)
pb[i]->mostrar();
// en tiempo de ejecución según el puntero elige a que
// función llamar. Late Binding o ligadura tardía
getch();
}
Yatay 240 - Buenos Aires - República Argentina
51 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
// ejemplo de sobrecarga de funciones en c++
#include<iostream.h>
#include<conio.h>
#include<string.h>
class base {
public:
int c;
int verc();
void setc(int i);
void p(){cout <<"p base";}
};
class derivada: public base{
int d; // privada por defecto
public:
int verd(){ return d;} // function inline
void setd(int i){ d=i;}
void veoc(){ cout<<"el valor de c es"<< c<<endl;}
void p(){cout <<"p deriv";}
};
int base::verc(){ return c; }
void base::setc(int i){
c=i;
}
void main(){
base b;
derivada d;
// instancia objeto clase base
// instancia objeto clase derivada
clrscr();
b.setc(10);
cout<<"el valor
d.setd(5);
cout<<"el valor
d.setc(1999);
cout<<"el valor
cout<<"el valor
d.veoc();
d.p();
getch();}
de c en b es"<< b.verc()<<endl;
de d en d es"<< d.verd()<<endl;
de c en d es"<< d.verc()<<endl;
de c en b es"<< b.verc()<<endl;
Yatay 240 - Buenos Aires - República Argentina
52 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Cabeceras provistas por el entorno
CONIO.H FUNCIONES
cgets, clreol, clrscr, cprintf, cuts, cscanf, delline, getch,getche,getpass, gettext, gettextinfo
gotoxy, highvideo, insline, inp,inport, inportb, inpw, kbhit lowvideo,movetext,normvideo, outp
outport, outportb,outpw, putch, puttext, setcursortype, textattr, textbackground, textcolor
textmode,ungetch, wherex wherey, window
STDIO.H FUNCIONES
Clearer, fclose, fcloseall, fdopen, feof, ferror, fflush, fgetc, fgetchar, fgetpos, fgets, fileno, flushall,
fopen, fprintf, fputc, fputchar, fputs, fread, freopen, fscanf, fseek, fsetpos, ftell, fwrite, getc, getchar
gets, getw, perror, printf, putc, putchar, puts, putw, remove, rename, rewind, rmtmp, scanf, setbuf
setvbuf, sprintf, sscanf, strerror, _strerror, tempnam,tmpfile, tmpnam, ungetc, unlink,fprintf
vfscanf,vprintf , vscanf, vsprintf, vsscanf
STRING.H FUNCIONES
_fmemccpy, _fmemchr, _fmemcmp, _fmemcpy, _fmemicmp _fmemset, _fstrcat, _fstrchr,
_fstrcmp, _fstrcpy, _fstrcspn, _fstrdup, _fstricmp, _fstrlen, _fstrlwr _fstrncat, _fstrncmp,
_fstrnicmp,_fstrncpy, _fstrnset _fstrpbrk, _fstrrchr, _fstrrev, _fstrset, _fstrspn _fstrstr, _fstrtok,
_fstrupr, memccpy,memchr memcmp, memcpy, memicmp,memmove,memset movedata,
movmem, setmem, stpcpy, strcat strchr, strcmp, strcmpi,strcpy, strcspn strdup, _strerror, strerror,
stricmp,strlen strlwr, strncat,strncmp,strncmpi, strncpy strnicmp, strnset,strpbrk,strrchr,strrev
strset, strspn, strstr, strtok, strxfrm strupr
Constants, data types, and global variables
size_t
STDLIB.H FUNCIONES
abort, abs,atexit,atof, atoi atol, bsearch, calloc,div,ecvt,exit, _exit, fcvt, free, _fullpath, gcvt,
getenv,itoa, labs, ldiv lfind, _lrotl,_lrotr,lsearch, ltoa _makepath,malloc,max,mblen, mbtowc
mbstowcs, min,putenv,qsort, rand
random,randomize,realloc, _rotl, _rotr _searchenv, _splitpath, srand, strtod,strtol
_strtold, strtoul, swab, system,time ultoa, wctomb,wcstombs
IO.H
Includes
STDARG.H
FUNCIONES
access, chmod, _chmod, chsize, close _close, creat, _creat, creatnew, creattemp dup, dup2,eof,
filelength,getftime ioctl, isatty, lock,locking,lseek mktemp, open,_open, read,_read
remove, rename, setftime, setmode,sopen tell,umask, unlink, unlock, write _write
CTYPE.H
_ftolower,_ftoupper,isalnum, isalpha, isascii, iscntrl isdigit, isgraph, islower, isprint, ispunct,
isspace isupper, isxdigit, toascii, tolower, toupper
Yatay 240 - Buenos Aires - República Argentina
53 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
APENDICE A - OBJETOS Y CLASES
A.1 Introducción
Los tipos definidos por el usuario o tipos abstractos de datos (TAD) empaquetan elementos dato con las
operaciones que se realizan sobre esos datos. C++ soporta los TAD con el tipo clase que puede ser
implementado con estructuras, uniones y clases.
A.2 Abstracción de datos
Una característica importante de cualquier lenguaje de programación es la capacidad de crear tipos de datos
definidos por el usuario. Aunque se pueden crear en C sus propios tipos, utilizando las palabras reservadas
typedef y struct, los tipos resultantes no se pueden integrar fácilmente en el resto del programa. Además, en C,
sólo se pueden definir los tipos en términos de datos; es decir, las funciones utilizadas para manipular esos tipos
no son parte de la definición del tipo.
Una definición de un tipo que incluye datos y funciones y el modo para encapsular los detalles, se conoce como
tipo abstracto de dato. En C++ se implementa mediante el uso de tipos de datos definidos por el usuario,
llamados clases.
clase = datos + funciones
Una diferencia importante entre C y C++, es que en C++ se pueden declarar funciones dentro de una estructura
(no se requiere declarar punteros a funciones). Las estructuras pueden tener también especificadas regiones de
acceso (medios en que se puede controlar el acceso a los datos).
La abstracción de datos en C++ se obtiene con los tipos de datos estructura (struct) y clase (class).
A.3 Concepto de clase
Una clase es un tipo de dato que contiene uno o más elementos dato llamados miembros dato, y cero, una o
más funciones que manipulan esos datos (llamadas funciones miembro). La sintaxis de una clase es:
class Nombre_clase{
miembro1;
miembro2;
...
funcion_miembro1();
funcion_miembro2();
...
};
Una clase es sintácticamente igual a una estructura, con la única diferencia de que en el tipo class todos los
miembros son por defecto privados mientras que en el tipo struct son por defecto públicos.
En C se utiliza el término variable estructura para referirse a una variable de tipo estructura. En C++ no se utiliza
el término variable de clase, sino instancia de la clase.
El término objeto es muy importante y no es más que una variable, que a su vez no es más que una instancia
de una clase.
Por consiguiente una clase es:
class Cliente{
char nom[20];
char num;
};
Yatay 240 - Buenos Aires - República Argentina
54 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
y un objeto de esta clase se declara:
cliente cli;
Una definición de una clase consta de dos partes: una declaración y una implementación. La declaración lista
los miembros de la clase. La implementación o cuerpo define las funciones de la clase.
Una de las características fundamentales de una clase es ocultar tanta información como sea posible. Por
consiguiente, es necesario imponer ciertas restricciones en el modo en que se puede manipular una clase y de
cómo se pueden utilizar los datos y el código dentro de una clase.
Una clase puede contener partes públicas y partes privadas. Por defecto, todos los miembros definidos en la
clase son privados. Para hacer las partes de una clase públicas (esto es, accesibles desde cualquier parte del
programa) deben declararse después de la palabra reservada public. Todas las variables o funciones definidas
después de public son accesibles a las restantes funciones del programa. Dado que una característica clave de
la POO es la ocultación de datos, debe tenerse presente que aunque se pueden tener variables públicas, desde
un punto de vista conceptual se debe tratar de limitar o eliminar su uso. En su lugar, deben hacerse todos los
datos privados y controlar el acceso a ellos a través de funciones públicas.
class Articulo{
private:
float precio;
char nombre[];
public:
void indicar();
};
Por defecto u omisión todo lo declarado dentro de una clase es privado y sólo se puede acceder a ello con las
funciones miembro declaradas en el interior de la clase o con funciones amigas.
Los miembros que se declaran en la sección protegida de una clase sólo pueden ser accedidos por funciones
miembro declaradas dentro de la clase, por funciones amigas o por funciones miembro de clases derivadas.
A los miembros que se declaran en la región pública de una clase se puede acceder a través de cualquier objeto
de la clase de igual modo que se accede a los miembros de una estructura en C.
class Alfa{
int x;
//miembros dato privados
float y;
char z;
public:
double k;
//miembro dato público
void fijar(int,float,char);
//funciones miembro públicas
void mostrar();
};
void main(){
alba obj;
//declaración de un objeto
obj.fijar(3,2.1,'a');
//invocar a una función miembro
obj.mostrar();
//invocar a una función miembro
obj.x=4; //error: no se puede acceder a datos privados
obj.k=3.2;
//válido: k está en la región pública
}
La definición de funciones miembro es muy similar a la definición ordinaria de función. Tienen una cabecera y un
cuerpo y pueden tener tipos y argumentos. Sin embargo, tienen dos características especiales:
a) Cuando se define una función miembro se utiliza el operador de resolución de ámbito (::) para identificar la
clase a la que pertenece la función.
b) Las funciones miembro (métodos) de las clases pueden acceder a las componentes privadas de la clase.
Yatay 240 - Buenos Aires - República Argentina
55 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Opción 1
Opción 2
class Ejemplo{
class Ejemplo{
int x,y;
public:
void f()
{
cout<<"x= "<<x<<" y= "<<y<<endl;
}
};
int x,y;
public:
void f();
};
void ejemplo::f()
{
cout<<"x= "<<x<<" y= "<<y<<endl;
}
En la primera opción la función está en línea (inline). Por cada llamada a esta función, el compilador genera
(vuelve a copiar) las diferentes instrucciones de la función. En la segunda opción (la más deseable) la función f
se llamará con una llamada verdadera de función.
La declaración anterior significa que la función f es miembro de la clase ejemplo. El nombre de la clase a la cual
está asociada la función miembro se añade como prefijo al nombre de la función. El operador :: separa el
nombre de la clase del nombre de la función. Diferentes clases pueden tener funciones del mismo nombre y la
sintaxis indica la clase asociada con la definición de la función.
A.4 Objetos
En C++ un objeto es un elemento declarado de un tipo clase. Se conoce también como una instancia de una
clase.
Los objetos se pueden tratar como cualquier variable C. La principal diferencia es que se puede llamar a
cualquiera de las funciones que pertenecen a un objeto, esto es, se puede enviar un mensaje a ella.
class Rectangulo{
int base;
int altura;
public:
void dimensiones(int,int);
int area();
};
void rectangulo::dimensiones(int b,int h){
base=b;
altura=h;
}
int rectangulo::area(){
return base*altura;
}
void main(){
Rectangulo r; //declarar el objeto
r.dimensiones(3,5); //definir el tamaño
cout<<"area "<<r.area();
}
A.5 Acceso a los miembros de una clase
A los miembros de una clase se accede de igual forma que a los miembros de una estructura. Existen dos
métodos para acceder a un miembro de una clase: el operador punto (.) y el operador flecha (->) que actúan de
modo similar.
class Contador{
public:
Yatay 240 - Buenos Aires - República Argentina
56 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
leer()
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
{return 1;}
};
void main(){
Contador c;
Contador *p = new(contador);
leer(); //error: función desconocida, no en ámbito
cout<<c.leer();
//correcto
cout<<p->leer();
//correcto
}
A.6 Clases vacías
Aunque el propósito de una clase es encapsular código y datos, una clase puede tener también una declaración
vacía.
class vacia{ };
Naturalmente, no se pueden realizar grandes cosas con esta clase, pero se pueden crear objetos de ella:
vacia obj;
Con frecuencia, en el desarrollo de un proyecto grande se necesitan comprobar implementaciones de primeras
versiones en las que algunas clases no están totalmente identificadas o implementadas todavía. Se suelen
denominar resguardos (stubs) y se diseñan para obtener códigos que se compilen sin errores, permitiendo
comprobar alguna parte de ellos.
A.7 Los miembros dato
La lista de miembros de una clase puede comprender cualquier tipo válido en C++. Puede contener tipos
primarios, estructuras e incluso punteros a cualquier tipo válido. Los miembros dato pueden ser incluso clases.
En cualquier caso sólo las instancias de clases definidas o declaradas previamente pueden ser miembros.
Los miembros dato declarados en la clase se deben considerar equivalentes a campos de una estructura, no a
variables. Tal como las estructuras, se debe declarar un objeto de un tipo clase y a continuación se inicializan
sus miembros dato.
Un miembro de una clase se puede declarar estático (static). Para un miembro dato, la designación static
significa que existe sólo una instancia de ese miembro. Un miembro dato estático es compartido por todos los
objetos de una clase.
A un miembro dato static se le asigna una zona fija de almacenamiento en tiempo de compilación, al igual que
una variable global, pero el identificador de la variable está dentro de ámbito utilizando solamente el operador ::
con el nombre de la clase.
Los miembros datos se asignan generalmente con la misma clase de almacenamiento. Para declarar o
inicializar un miembro static se utiliza la misma notación que una variable global.
class Ejemplo{
public:
static int valor;
//declarar miembro estático
};
int ejemplo::valor;
//definir miembro estático
void main(){
ejemplo e1,e2;
e1.valor=1;
e2.valor=10;}
Yatay 240 - Buenos Aires - República Argentina
57 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
A los miembros dato static se puede acceder:
1. Utilizando el operador punto
2. Utilizando el operador flecha, si el lado izquierdo es un puntero a objeto
3. Utilizando el identificador de la clase sin referenciar un objeto real: ejemplo::valor=3;
Los miembros datos static no siempre tienen que ser public.
class Ejemplo{
private:
static int valor;
//declarar miembro estático
};
int ejemplo::valor=5; //definir miembro estático
void main(){
ejemplo e1;
e1.valor=1;
//error: aceso no válido
}
Para acceder a un miembro dato private static se necesita utilizar el operador ::
Otros medios son:
1.- A través de una función miembro de la clase
2.- A través de una función declarada amiga de la clase
A.8 Ámbito de una clase
Una clase actúa como cualquier otro tipo de dato con respecto al ámbito. Todos los miembros de una clase se
dice que están en el ámbito de esa clase; cualquier miembro de una clase puede referenciar a cualquier otro
miembro de la misma clase.
Las funciones miembro de una clase tienen acceso no restringido a los miembros dato de esa clase. El acceso
a los miembros dato y funciones de una clase fuera del ámbito de la clase está controlado por el programador.
La idea es encapsular la estructura de datos y funcionalidad de una clase, de modo que el acceso a la
estructura de datos de la clase desde fuera de las funciones miembro de la clase, sea limitada o innecesaria.
El nombre de la clase tiene que ser único dentro de su ámbito.
A.9 Especificadores de acceso a los miembros de una clase
En una definición de clase, un especificador de acceso se utiliza para controlar la visibilidad de los miembros de
una clase fuera del ámbito de la clase.
Los miembros de una clase pueden ser públicos, privados o protegidos.
Las palabras reservadas public, private y protected se utilizan para controlar el modo de acceso a la clase.
Dentro de una declaración de clase, cada una de estas palabras se puede utilizar para preceder a una o más
declaraciones de los miembros de una clase
Acceso protegido. Los miembros protegidos significan que sólo se puede acceder a ellos por funciones miembro
dentro de la misma clase y por funciones miembro de clases derivadas de esta clase.
Acceso público. Los miembros públicos son accesibles por cualquier parte del programa.
Acceso privado. Los miembros privados sólo pueden ser utilizados por las funciones miembro de la clase y las
funciones amigas de la clase.
A.10 Funciones miembro
Las funciones miembro son miembros de una clase y son funciones diseñadas para implementar las
operaciones permitidas sobre los tipos de datos de una clase. Para declarar una función miembro hay que situar
su prototipo en el cuerpo de la clase. No hay que definir la función dentro de la clase; dicha definición puede
estar fuera de la clase e incluso en un archivo independiente, aunque también pueden ser definidas en línea
dentro de la clase.
Yatay 240 - Buenos Aires - República Argentina
58 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Las funciones miembro son necesarias para acceder a los datos privados. En general, son públicas; si no lo
fueran, ninguna otra función podría llamarlas. Se pueden declarar para devolver valores con tipos incluyendo
objetos de clases, punteros o referencias. Pueden ser declaradas también para aceptar cualquier número y tipo
de argumentos. Los argumentos por defecto están permitidos, así como la notación de puntos suspensivos.
A.11 El puntero this
Nunca se puede llamar a una función miembro privada de una clase a menos que se asocie con un objeto. En C
cada vez que se utiliza un puntero para acceder a los miembros de una estructura, debe utilizarse el operador
de puntero (->) para acceder a los datos. ¿Cómo sabe una función miembro cuál es la instancia de una clase
asociada con ella?
El método utilizado por C++ es añadir un argumento extra oculto a las funciones miembro. Este argumento es
un puntero al objeto de la clase que lo enlaza con la función asociada y recibe un nombre especial denominado
this.
Dentro de una función miembro, this apunta al objeto asociado con la invocación de la función miembro. El tipo
de this en una función miembro de una clase T es T *const es decir, un puntero constante a un objeto de tipo
T.
Normalmente, el programador no necesita preocuparse por este puntero, ya que C++ realiza la operación
automáticamente, haciendo el uso de this transparente a las funciones miembro que la utilizan. Dentro de una
función miembro, se pueden hacer referencias a los miembros del objeto asociado a ella con el prefijo this y el
operador de acceso ->. Sin embargo, este proceso no es necesario, ya que es redundante. Consideremos como
ejemplo el constructor de una clase que manipula números complejos:
complejo::complejo (float a,float b){
real=a;
imag=b;
}
Este constructor se puede escribir:
complejo::complejo (float a,float b){
this->real=a;
this->imag=b;
}
this->nombre_miembro : apunta a un miembro
*this : es el objeto total. Es un valor constante
this : es la dirección del objeto apuntado
A.12 Funciones miembro estáticas
Las funciones miembro static sólo pueden acceder a otras funciones y datos declarados en una clase, pero no
pueden manipular funciones ni datos no estáticos. La razón de esta característica es que una función miembro
static no tiene asignado un puntero this y por ello no puede acceder a miembros dato de la clase a menos que
se pase explícitamente este puntero this.
A.13 Constructores
Un constructor es una función especial que sirve para inicializar objetos. En C++ la inicialización de objetos no
se puede realizar en el momento en que son declarados; sin embargo, tiene una característica muy importante y
es disponer de una función llamada constructor que permite inicializar objetos en el momento en que se crean.
Un constructor es una función que sirve para asignar valores a sus miembros dato. Se caracteriza por:
- Tener el mismo nombre de la clase que inicializa
- Puede definirse inline o fuera de la declaración de la clase
- No devuelve valores
- Puede admitir parámetros como cualquier otra función
- Puede existir más de un constructor(sobrecarga de funciones), e incluso no existir
Yatay 240 - Buenos Aires - República Argentina
59 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Si no se define ningún constructor de una clase, el compilador generará un constructor por defecto. El
constructor por defecto no tiene argumentos y simplemente sitúa ceros en cada byte de las variables instancia
de un objeto. Si se definen constructores para una clase, el constructor por defecto no se genera.
Un constructor del objeto se llama cuando se crea el objeto implícitamente: nunca se llama explícitamente a las
funciones constructoras. Esto significa que se llama cuando se ejecuta la declaración del objeto. También, para
objetos locales, el constructor se llama cada vez que la declaración del objeto se encuentra. En objetos
globales, el constructor se llama cuando se arranca el programa.
El constructor por defecto es un constructor que no acepta argumentos. Se llama cuando se define una
instancia pero no se especifica un valor inicial.
Se pueden declarar en una clase constructores múltiples, mientras tomen parte diferentes tipos o número de
argumentos(sobrecarga de funciones). El compilador es entonces capaz de determinar automáticamente a qué
constructor llamar en cada caso, examinando los argumentos.
Los argumentos por defecto se pueden especificar en la declaración del constructor. Los miembros dato se
inicializarán a esos valores por defecto, si ningún otro se especifica.
C++ ofrece un mecanismo alternativo para pasar valores de parámetros a miembros dato. Este mecanismo
consiste en inicializar miembros dato con parámetros.
class Prueba{
tipo1 d1;
tipo2 d2;
tipo3 d3;
public:
prueba(tipo1 p1, tipo2 p2, tipo3 p3):d1(p1),d2(p2),d3(p3)
{ }
};
Un constructor que crea un nuevo objeto a partir de uno existente se llama constructor copiador o de copias. El
constructor de copias tiene sólo un argumento: una referencia constante a un objeto de la misma clase. Un
constructor copiador de una clase complejo es:
complejo::complejo(const complejo &fuente){
real=fuente.real;
imag=fuente.imag;
}
Si no se incluye un constructor de copia, el compilador creará un constructor de copia por defecto. Este sistema
funciona de un modo perfectamente satisfactorio en la mayoría de los casos, aunque en ocasiones puede
producir dificultades. El constructor de copia por defecto inicializa cada elemento de datos del objeto a la
izquierda del operador = al valor del elmento dato equivalente del objeto de la derecha del operador =. Cuando
no hay punteros invicados, eso funciona bien. Sin embargo, cuando se utilizan punteros, el constructor de
copia por defecto inicializará el valor de un elemento puntero de la izquierda del operador = al del
elemento equivalente de la derecha del operador; es decir que los dos punteros apuntan en la misma
dirección. Si ésta no es la situación que se desea, hay que escribir un constructor de copia.
A.14 Destructores
Un destructor es una función miembro con igual nombre que la clase, pero precedido por el carácter ~. Una
clase sólo tiene una función destructor que, no tiene argumentos y no devuelve ningún tipo. Un destructor
realiza la operación opuesta de un constructor, limpiando el almacenamiento asignado a los objetos cuando se
crean. C++ permite sólo un destructor por clase. El compilador llama automáticamente a un destructor del objeto
cuando el objeto sale fuera del ámbito. Si un destructor no se define en una clase, se creará por defecto un
destructor que no hace nada.
Normalmente los destructores se declaran public.
A.15 Creación y supresión dinámica de objetos
Los operadores new y delete se pueden utilizar para crear y destruir objetos de una clase, así como dentro de
funciones constructoras y destructoras.
Yatay 240 - Buenos Aires - República Argentina
60 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Un objetro de una determinada clase se crea cuando la ejecución del programa entra en el ámbito en que está
definida y se destruye cuando se llega al final del ámbito. Esto es válido tanto para objetos globales como
locales, ya que los objetos globales se crean al comenzar el programa y se destruyen al salir de él. Sin
embargo, se puede crear un objeto también mediante el operador new, que asigna la memoria necesaria para
alojar el objeto y devuelve su dirección, en forma de puntero, al objeto en cuestión.
Los constructores normalmente implican la aplicación de new.
p =new int(9) //p es un puntero a int inicializado a 9
cadena cad1("hola");
cadena *cad2=new cadena;
Un objeto creado con new no tiene ámbito, es decir, no se destruye automáticamente al salir fuera del ámbito,
sino que existe hasta que se destruye explícitamente mediante el operador delete.
class Cadena {
char *datos;
public:
cadena(int);
~cadena();
};
cadena::cadena(int lon){
datos=new char[lon];
}
cadena::~cadena(){
delete datos;
}
A.16 Funciones amigas
Una función amiga es una función no miembro de una clase que puede tener acceso a las partes privadas de
una clase; se debe declarar como amiga de la clase mediante la palabra reservada friend.
Las funciones amigas se declaran situando su prototipo de función en la clase de la que son amiga
precediéndola con la palabra reservada friend. Por ejemplo:
class Cosa{
int datos;
public:
friend void cargar (cosa& t, int x);
};
void cargar(cosa& t, int x){
t.datos=x;
}
Como la función cargar se declara amiga de la clase cosa puede acceder al miembro privado datos.
Las razones fundamentales para utilizar funciones amigas es que algunas funciones necesitan acceso
privilegiado a más de una clase. Una segunda razón es que las funciones amigas pasan todos sus argumentos
a través de la lista de argumentos y cada valor de argumento se somete a la conversión de asignación.
Yatay 240 - Buenos Aires - República Argentina
61 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
B.- HERENCIA Y JERARQUIA DE CLASES
B.1 Introducción
Una de las propiedades más importantes de la POO es la abstracción de datos. Esta propiedad se manifiesta
esencialmente en la encapsulación, que es la responsable de gestionar la complejidad de grandes programas al
permitir la definición de nuevos tipos de datos: las clases.
Sin embargo, la clase no es suficiente por sí sola para soportar diseño y programación orientada a objetos. Se
necesita un medio para relacionar unas clases con otras. Un medio son las clases anidadas, pero sólo se
resuelve parcialmente el problema, ya que las clases anidadas no tienen las características requeridas para
relacionar totalmente una clase con otra. Se necesita un mecanismo para crear jerarquías de clases en las que
la clase A sea afín a la clase B, pero con la posibilidad de poder añadirle también características propias. Este
mecanismo es la herencia.
La herencia es, seguramente, la característica más potente de la POO, después de las clases. Por herencia
conocemos el proceso de crear nuevas clases, llamadas clases derivadas, a partir de una clase base.
En C++ la herencia se manifiesta con la creación de un tipo definido por el usuario (clase), que puede heredar
las características de otra clase ya existente o derivar las suyas a otra nueva clase. Cuando se hereda, las
clases derivadas reciben las características (estructuras de datos y funciones) de la clase original, a las que se
pueden añadir nuevas características o modificar las características heredadas. El compilador hace realmente
una copia de la clase base en la nueva clase derivada y permite al programador añadir o modificar miembros sin
alterar el código de la clase base.
La derivación de clases consigue la reutilización efectiva del código de la clase base para sus
necesidades. Si se tiene una clase base totalmente depurada, la herencia ayuda a reutilizar ese código
en una nueva clase. No es necesario comprender el código fuente de la clase original, sino sólo lo que
hace.
B.2 Clases derivadas
En C++, la herencia simple se realiza tomando una clase existente y derivando nuevas clases de ella. La clase
derivada hereda las estructuras de datos y funciones de la clase original. Además, se pueden añadir nuevos
miembros a las clases derivadas y los miembros heredados pueden ser modificados.
Una clase utilizada para derivar nuevas clases se denomina clase base, clase padre, superclase o ascendiente.
Una clase creada de otra clase se denomina clase derivada o subclase.
Se pueden construir jerarquías de clases, en las que cada clase sirve como padre o raíz de una nueva clase.
B.3 Conceptos fundamentales de derivación
C++ utiliza un sistema de herencia jerárquica. Es decir, se hereda una clase de otra, creando nuevas clases a
partir de las clases ya existentes. Sólo se pueden heredar clases, no funciones ordinarias n variables, en C++.
Una clase derivada hereda todos los miembros dato excepto, miembros dato estáticos, de cada una de sus
clases base.
Una clase derivada hereda las funciones miembro de su clase base. Esto significa que se hereda la capacidad
para llamar a funciones miembro de la clase base en los objetos de la clase derivada.
Los siguientes elementos de la clase no se heredan:
- Constructores
- Destructores
- Funciones amigas
- Funciones estáticas de la clase
- Datos estáticos de la clase
- Operador de asignación sobrecargado
Yatay 240 - Buenos Aires - República Argentina
62 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Las clases base diseñadas con el objetivo principal de ser heredadas por otras se denominan clases abstractas.
Normalmente, no se crean instancias a partir de clases abstractas, aunque sea posible.
B.4 La herencia en C++
En C++ existen dos tipos de herencia: simple y múltiple. La herencia simple es aquella en la que cada clase
derivada hereda de una única clase. En herencia simple, cada clase tiene un solo ascendiente. Cada clase
puede tener, sin embargo, muchos descendientes.
La herencia múltiple es aquella en la cual una clase derivada tiene más de una clase base. Aunque el concepto
de herencia múltiple es muy útil, el diseño de clases suele ser más complejo.
B.5 Creación de una clase derivada
Cada clase derivada se debe referir a una clase base declarada anteriormente.
La declaración de una clase derivada tiene la siguiente sintaxis:
class clase_derivada:<especificadores_de_acceso> clase_base {...};
Los especificadores de acceso pueden ser: public, protected o private.
B.6 Clases de derivación
Los especificadores de acceso a las clases base definen los posibles tipos de derivación: public, protected y
private. El tipo de acceso a la clase base especifica cómo recibirá la clase derivada a los miembros de la clase
base. Si no se especifica un acceso a la clase base, C++ supone que su tipo de herencia es privado.
- Derivación pública (public). Todos los miembros public y protected de la clase base son accesibles en la clase
derivada, mientras que los miembros private de la clase base son siempre inaccesibles en la clase derivada.
- Derivación privada (private). Todos los miembros de la clase base se comportan como miembros privados de
la clase derivada. Esto significa que los miembros public y protected de la clase base no son accesibles más
que por las funciones miembro de la clase derivada. Los miembros privados de la clase siguen siendo
inaccesibles desde la clase derivada.
- Derivación protegida (protected). Todos los miembros public y protected de la clase base se comportan como
miembros protected de la clase derivada. Estos miembros no son, pues, accesibles al programa exterior, pero
las clases que se deriven a continuación podrán acceder normalmente a estos miembros (datos o funciones).
B.7 Constructores y destructores en herencia
Una clase derivada puede tener tanto constructores como destructores, aunque tiene el problema adicional de
que la clase base puede tomar ambas funciones miembro especiales.
Un constructor o destructor definido en la clase base debe estar coordinado con los encontrados en una clase
derivada. Igualmente importante es el movimiento de valores de los miembros de la clase derivada a los
miembros que se encuentran en la base. En particular, se debe considerar cómo el constructor de la clase
base recibe valores de la clase derivada para crear el objeto completo.
Si un constructor se define tanto para la clase base como para la clase derivada, C++ llama primero al
constructor base. Después que el constructor de la base termina sus tareas, C++ ejecuta el constructor
derivado.
Cuando una clase base define un constructor, éste se debe llamar durante la creación de cada instancia de una
clase derivada, para garantizar la buena inicialización de los datos miembro que la clase derivada hereda de la
clase base. En este caso la clase derivada debe definir a su vez un constructor que llama al constructor de la
clase base proporcionándole los argumentos requeridos.
Un constructor de una clase derivada debe utilizar un mecanismo de pasar aquellos argumentos requeridos por
el correspondiente constructor de la clase base.
Yatay 240 - Buenos Aires - República Argentina
63 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
derivada::derivada(tipo1 x, tipo2 y): base (x, y) {...}
nota : x e y en base pasan como argumentos no se coloca el tipo
Otro aspecto importante que es necesario considerar es el orden en el que el compilador C++ inicializa las
clases base de una clase derivada. Cuando El compilador C++ inicializa una instancia de una clase derivada,
tiene que inicializar todas las clases base primero.
Por definición, un destructor de clases no toma parámetros.
Al contrario que los constructores, una función destructor de una clase derivada se ejecuta antes que el
destructor de la clase base.
B.8 Redefinición de funciones miembro heredadas
Se pueden utilizar funciones miembro en una clase derivada que tengan el mismo nombre que otra de una clase
base.
La redefinición de funciones se realiza mediante funciones miembro sobrecargadas en la clase derivada. Una
función miembro redefinida oculta todas las funciones miembro heredadas del mismo nombre. Por tanto cuando
en la clase base y en la clase derivada hay una función con el mismo nombre en las dos, se ejecuta la función
de la clase derivada.(invalidación de metodo)
B.9 Herencia múltiple
Es la propiedad con la cual una clase derivada puede tener más de una clase base. Es más adecuada para
definir objetos que son compuestos, por naturaleza, tales como un registro personal, un objeto gráfico.
Sólo es una extensión de la sintaxis de la clase derivada. Introduce una cierta complejidad en el lenguaje y el
compilador, pero proporciona grandes beneficios.
class ejemplo: private base1, private base2 {...};
La aplicación de clases base múltiples introduce un conjunto de ambigüedades a los programas C++. Una de
las más comunes se da cuando dos clases base tienen funciones con el mismo nombre, y sin embargo, una
clase derivada de ambas no tiene ninguna función con ese nombre. ¿ Cómo acceden los objetos de la clase
derivada a la función correcta de la clase base ? El nombre de la función no es suficiente, ya que el compilador
no puede deducir cuál de las dos funciones es la invocada.
Si se tiene una clase C que se deriva de dos clases base A y B, ambas con una función mostrar() y se define un
objeto de la clase C: C objetoC, la manera de resolver la ambigüedad es utilizando el operador de resolución de
ámbito:
objetoC.A::mostrar(); //se refiere a la versión de //mostrar() de la clase A
objetoC.B::mostrar(); //se refiere a la versión de //mostrar() de la clase B
Yatay 240 - Buenos Aires - República Argentina
64 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
B.10 Constructores y destructores en herencia múltiple
El uso de funciones constructor y destructor en clases derivadas es más complejo que en una clase simple. Al
crear clases derivadas con una sola clase base, se observa que el constructor de la clase base se llama
siempre antes que el constructor de la clase derivada.
Además se dispone de un mecanismo para pasar los valores de los parámetros necesarios al constructor base
desde el constructor de la clase derivada. Así, la sentencia siguiente pasa el puntero a carácter x y el valor del
entero y a la clase base:
derivada (char *x, int y, double z): base(x,y)
Este método se expande para efectuar más de una clase base.La sentencia:
derivada (char *x,int y, double z): base1(x),base2(y)
Llama al constructor base1 y pasa el valor de cadena de caracteres x y al constructor base2 le proporciona un
valor entero y. Como con la herencia simple, los constructores de la clase base se llaman antes de que se
ejecuten al constructor de la clase derivada. Los constructores se llaman en el orden en que se declaran las
clases base.
De modo similar, las relaciones entre el destructor de la clase derivada y el destructor de la clase base se
mantiene. El destructor derivado se llama antes de que se llame a los destructores de cualquier base. Los
destructores de las clases base se llaman en orden inverso al orden en que los objetos base se crearon.
B.11 Herencia repetida
La primera regla de la herencia múltiple es que una clase derivada no puede heredar más de una vez de una
sola clase, al menos no directamente. Sin embargo, es posible que una clase se pueda derivar dos o más veces
por caminos distintos, de modo que se puede reprtir una clase. La propiedad de recibir por herencia una misma
clase más de una vez se conoce como herencia repetida.
B.12 Clases base virtuales
Una clase base virtual es una clase que es compartida por otras clases base con independencia del número de
veces que esta clase se produce en la jerarquía de derivación. Suponer , por ejemplo, que la clase T se deriva
de las clases C y D cada una de las cuales se deriva de la clase A. Esto significa que la clase T tiene dos
instancias de A en su jerarquía de derivación. C++ permite instancias múltiples de la misma clase base. Sin
embargo, si sólo se desea una instancia de la clase A para la clase T, entonces se debe declarar A como una
clase base virtual.
Las clases base virtuales proporcionan un método de anular el mecanismo de herencia múltiple, permitiendo
especificar una clase que es una clase base compartida.
Una clase derivada puede tener instancias virtuales y no virtuales de la misma clase base.
Yatay 240 - Buenos Aires - República Argentina
65 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
APENDICE DE PUNTEROS Y ARREGLOS
En C, hay una fuerte relación entre los punteros y arreglos, de manera que punteros y arreglos deberán ser
tratados simultáneamente. Alguna operación que puede ser lograda por suscripción de arreglo, puede ser
también hecha con punteros. La versión del puntero en general será rápida pero, pero por lo menos para el
no iniciado, algo difícil de asimilar rápidamente.
La declaración
int a [10];
define un arreglo de largo 10, esto es un bloque de 10 objetos consecutivos llamados a [0] a[ 1],..,a[ 9] . La
notación a[i] quiere decir que el elemento i del arreglo se posiciona desde el comienzo. Si pa es un puntero
para un entero, declarado como
int *pa
entonces el asignamiento
pa = &a[0]
coloca pa apuntando el elemento cero de a; este es, pa contiene la dirección de a[0] .Ahora el asignamiento
x = *pa
copiara el contenido de a[0] en x.
Si pa apunta a un elemento particular de un arreglo a, entones por definición pa+1 apunta al próximo
elemento, y en general pa-i apunta i elementos antes de pa, y pa+i apunta i elementos después.
Así, si pa apunta a [0] ,
*(pa+1)
se refiere al contenido de a[1] , pa+1 es la dirección de a[i] , y *(pa+i) es el contenido de a[i] .
Estas observaciones son verdaderas, descuidado el tipo de las variables en el arreglo a. La definición de
"sumando 1 al puntero", y por extensión, todo puntero aritmético, es que el incremento esta escalado
por el largo en almacenaje del objeto que es apuntado. Así en pa+i, i es multiplicado por el largo de los
objetos que pa apunta de que sea sumado a pa.
La correspondencia entre indexar y un puntero aritmético es evidentemente muy cerrada. En efecto, una
referencia para un arreglo es convertido por el compilador a un puntero al comienzo del arreglo.
El efecto es que un nombre de arreglo es una expresión puntero. Esto tiene unas pocas implicaciones
útiles ya que el nombre de un arreglo es un sinónimo para la localización del elemento cero, el asignamiento.
pa = &a[0]
también puede ser escrito como
pa = a
Mas sorpresa, por lo menos a primera vista, es el hecho que una referencia a[i] también puede ser escrita
como *(a+i). Evaluando a[i] , C lo convierte a *(a+i) inmediatamente; las dos formas son completamente
equivalentes. Aplicando el operador & a ambas partes de esta equivalencia, lo sigue ese &a[i] y a+i son
también idénticos: a+i es la dirección del i-esimo elemento después de a. Como el otro lado de esta
moneda, si pa es un puntero, las expresiones pueden usarlo con un subíndice: pa[i] es idéntico a *(pa+i). En
corto, algún arreglo e índice de expresión pueden ser escritos como un puntero y offset, y viceversa, aún en
la misma instrucción.
Hay una diferencia entre un nombre de arreglo y un puntero que debe tenerse presente. Un puntero es una
variable, así pa=a y pa++ son operaciones con sentido. Pero un nombre de arreglo es una constante, no
una variable: construcciones como a=pa o a++ son ilegales.
Cuando un nombre de arreglo es pasado a una función, lo que pasa es la ubicación del comienzo del arreglo.
Dentro de la función llamada, este argumento es una variable, justo como alguna otra variable, y así un
argumento de nombre de arreglo es verdaderamente un puntero, esto es, una variable conteniendo una
dirección. Podemos usar este hecho para escribir una nueva versión de strlen, que calcula el largo de un
string.
Yatay 240 - Buenos Aires - República Argentina
66 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
int strlen(char s[]){
// devuelve largo del string s
int i=0;
wile(s[i] != '\0')
++i;
return i ;
}
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
int strlen(char *s){
// devuelve el largo del string s
int n;
for (n = 0; *s != '\0'; s++)
n++;
return n;
}
La siguiente función strlen(s) devuelve el largo del string de caracteres s excluyendo el ultimo ‘\0’.Incrementar
s es perfectamente legal, ya que es una variable puntero; s++ no tiene efecto sobre el carácter de string
en la función que llama strlen, pero strlen incrementa una copia privada de la dirección.
Como parámetros formales en una definición de función,
char s[];
y
char *s;
son exactamente equivalentes; que debería ser escrito está determinado considerablemente por cuantas
expresiones serán escritas en la función.
Cuando un nombre de arreglo es pasado a una función, la función puede creer a su conveniencia que ha sido
dirigida por un arreglo o un puntero, y manipularla de consiguiente. Hasta puede usar ambas clases de
operaciones si lo ve apropiado y claro.
Es posible pasar parte de un arreglo a una función, pasando un puntero al comienzo del sub-arreglo. Por
ejemplo, si a es un arreglo,
f(&a [2] )
y
f(a+2)
ambas pasan a la función f la dirección del elemento a 2 , porque &a 2 y a+2 son ambas expresiones
punteros que se refieren al tercer elemento de a. Dentro de f la declaración de argumento puede leer.
f(int arr[ ])
o
f(int *arr)
Así hasta f está ocupado, el hecho de que el argumento realmente se refiera a la parte de un gran arreglo, no
es de consecuencia.
DIRECCIÓN ARITMÉTICA
Si p es un puntero, entonces p++ incrementa p apuntando al próximo elemento (un objeto de cualquier clase),
y p += i incrementa p apuntando al elemento i después de donde actualmente lo hace.
Estas y construcciones similares son la mas simple y común forma de puntero o dirección aritmética.
C es consistente y regular en su aproximación a las direcciones aritméticas; su integración de punteros,
arreglo y dirección aritmética es una de las mayores fuerzas del lenguaje
Los punteros deben ser comparados bajo ciertas circunstancias. Si p y q apuntan a miembros del mismo
arreglo, entonces relaciones como <, >=, etc., trabajan apropiadamente.
p<q
es verdadero, por ejemplo, si p apunta a un miembro del arreglo antes de que lo haga q.
Las relaciones == y != también trabajan. Algún puntero puede ser completamente comparado por igualdad o
desigualdad con NULL. Pero todas las apuestas están fuera si Ud. hace aritmética o comparaciones con
punteros apuntando a diferentes arreglos.
Si Ud. Es afortunado, obtendría un disparate en todas las máquinas. Si Ud. No tiene suerte, su código
trabajar en una máquina, pero se derrumbar misteriosamente en otra.
Segundo, ya hemos observado que un puntero y un entero pueden ser sumados o restados.
La construcción
p+n
significa que el n-simo objeto es apuntado por el p en curso. Esto es verdad descuidando el genero del
objeto, p es declarado para apuntar a; el compilador gradúa n de acuerdo al largo de los objetos que apunta
p, que está determinado por la declaración de p. Por ejemplo, en el PDP-11, las escalas de factores son 1
para char, 2 para int y short, 4 para long y float, y 8 para doble.
Yatay 240 - Buenos Aires - República Argentina
67 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
La substracción de punteros es también valida: si p y q apuntan a miembros del mismo arreglo, p-q es el
número de elementos entre p y q. Este hecho puede ser usado para escribir otra versión de strlen:
int strlen(char *s){// devuelve largo de string s
char *p = s;
while (*p != '\0')
p++;
return(p-s);
}
En la declaración, p es inicializado en s, esto es, apunta al primer carácter. En el while, cada carácter es
examinado hasta que \0 es visto al final. Ya que \0 es cero, es posible omitir la pregunta explicita, y cada
loop es escrito frecuentemente como
while(*p)
p++;
Porque p apunta a caracteres, p++ avanza p al próximo carácter cada vez, y p-s entrega el número de
caracteres avanzados, esto es, el largo del string. El puntero aritmético es consistente; si hemos estado
procediendo con float's, que ocupan mas almacenaje que los char's, meramente cambiando char a float por
todo alloc y free.
Todas las manipulaciones automáticamente toman los punteros considerando el largo del objeto apuntado,
así ningún otro ha de ser alterado.
Otra de las operaciones mencionadas aquí¡ (sumando o restando un puntero y un entero; restando o
comparando dos punteros), todo otro puntero aritmético es ilegal. No está permitido, multiplicar, dividir,
desviar u ocultarlos, o sumar float o doble a ellos.
PUNTEROS DE CARACTERES Y FUNCIONES
Un string constante, escrito como "yo soy un string"
es un arreglo de caracteres. En la representación interna, el compilador termina el arreglo con el carácter \0
así ese programa puede encontrar el final. El largo en almacenaje es así, uno mas que el número de
caracteres entre comillas.
Quizá la ocurrencia mas común de string constante es como argumento para función, como en
cout<<"Hola, mundo\n";
Cuando un string de carácter como este aparece en un programa, lo accesa a través de un puntero carácter;
lo que cout recibe es un puntero para el arreglo de carácter.
Los arreglos de carácter en curso no necesitan ser argumentos de función. Si message es declarado como
char *message
entonces la instrucción
char *message = "ahora es tiempo";
asigna a message un puntero para los caracteres actuales. Esto no es una copia del string; solo involucra
punteros. C++ no proporciona algunos operadores, para procesar un string completo con caracteres, como
una unidad.
Ilustraremos mas aspectos de punteros y arreglos estudiando dos funciones útiles desde la biblioteca
standard de I/O.
La primera función es strcpy(s, t), que copia el string t al string s. Los argumentos son escritos en este orden
por analogía al asignamiento, donde uno podría decir
s = t
para asignar t a s.
La primera versión del arreglo es:
void strcpy(char s[], t[]){
// copia t a s
int i;
i = 0;
while ((s[i] = t[i]) != '\0’)
i++;
}
Por el contrario, hay una versión de strcpy con punteros.
Yatay 240 - Buenos Aires - República Argentina
68 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
void strcpy(char *s, *t){
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
// copia t a s; versión 1, con puntero
while ((*s = *t) != '\0'){
s++;
t++;
}
Porque los argumentos son pasados por valor, strcpy puede usar s y t en la forma que guste. Aquí los
punteros son convenientemente inicializados, que son puestos en marcha a lo largo de los arreglos un
carácter a la vez, hasta que el ‘\0’ que termina t ha sido copiado a s.
En la práctica, strcpy no debería ser escrito como mostramos arriba.
Una segunda posibilidad puede ser
Void strcpy(char *s, char *t){
while ((*s++ = *t++) != '\0')
;
// copia t a s; versión 2, con punteros
Esto mueve el incremento de s y t dentro de la parte de la pregunta. El valor de *t++ es el carácter que
apunta t antes de que t fuera incrementado; el sufijo ++ no cambia t hasta después de que este carácter ha
sido traído. En la misma forma, el carácter es almacenado en la antigua posición s antes que s sea
incrementado. Este carácter es también el valor que es comparado contra ‘\0’ para controlar el loop. El efecto
neto es que los caracteres son copiados desde t a s incluyendo la terminación ‘ \0’.
Como la abreviación final, observemos nuevamente que una comparación contra 0 es redundante, así la
función es frecuentemente escrita como
void strcpy(char *s, char *t){
while(*s++ = *t++)
;
}
// copia t a s; versión 3, con punteros
Aunque esto puede parecer escondido a primera vista, la conveniencia notacional es considerable, y el
idioma debería ser de amplia difusión.
Yatay 240 - Buenos Aires - República Argentina
69 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Ejemplos de funciones que manejan cadenas de caracteres en C y C++
int
int
int
int
int
void
void
void
void
void
char
void
len(char s[]);
len2(char *s);
len3(char *s);
len4(char *s);
len5(char *s);
copy(char s[], char p[]);
copy1(char *s, char *p);
copy2(char *s, char *p);
copy3(char *s, char *p);
copy4(char *s, char *p);
* copy5(char *s, char *p);
copymal(char *s, char *p);
// longitud de una cadena de caracteres
int len(char s[]){
// ejemplo con subindices
int i=0;
while(s[i]!='\0'){
i++;
}
return i;
}
int len2(char *s){
// s es una variable local y no modifica al argumento por eso se puede incrementar
int i=0;
while(*s!='\0'){
s++;
i++;
}
return i;
}
int len3(char *s){
int i=0;
while(*s){ // la condicion !='\0' se puede sacar ya que es redundante
s++;
i++;
}
return i;
}
int len4(char *s){
int i=0;
while(*s++){
i++;
}
return i;
}
int len5(char *s){
char *p=s;
while(*p){
p++;
}
return p-s;
}
//
//
//
//
//numero de caracteres avanzados
// copia una cadena a otra
void copy(char s[], char p[]){
int i=0;
while((s[i]=p[i])!='\0'){
i++;
}
Yatay 240 - Buenos Aires - República Argentina
ejemplo con aritmética de punteros (resta)
apunta al primer carácter
si es while (*p++) debe devolver p-s-1
avanza al sig. carácter
// ejemplo con subindices
70 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
}
void copy1(char *s, char *p){ // ejemplo con punteros
// no se modifica los punteros porque son copias s y p son variables locales
while((*s=*p)!='\0'){
s++;
p++;
}
}
void copy2(char *s, char *p){
while((*s++ = *p++)!='\0')
;
}
void copy3(char *s, char *p){
// la condicion de !='\0' se puede eliminar por ser redundante
while(*s++ = *p++)
;
}
void copy4(char *s, char *p){
while(*s=*p){
s++;
p++;
}
}
char * copy5(char *s, char *p){
char *t=s;
// guarda la primera posición de s en t
while(*s=*p){
s++;
p++;
}
return t;
// devuelve la primera oposición de s
}
void copymal(char *s,char *p){ // no funciona copia punteros no contenidos !!!!!
s=p;
}
void main(){
char sp[]="hola que tal";
char s[100];
cout<<"->"<< sp <<"<- largo de s: "<<len5(sp)<<endl;
// no se modifica el puntero de sp adentro de len porque es una copia
copy(s,sp);
// uso de copy modificando s
cout<<"->"<<s<<"<- largo de s: "<<strlen(s)<<endl;
copy(s,"");
cout<<"->"<< copy5(s,sp) << "<- largo de s: "<<len4(s); // uso de copy como función
}
Yatay 240 - Buenos Aires - República Argentina
71 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Ejemplo de utilización de punteros para determinar el fin de un vector y typedef
#define MAX 5
typedef int tipo;
tipo vec[MAX]={4,2,5,1,3};
tipo max(float *v);
// define un tipo propio
// ejemplo de utilización de punteros para determinar el fin de un vector
tipo max(tipo *v){
tipo max= *v;
tipo *p=v;
// almacena la dirección del 1 elemento del vector en un puntero
for ( ; (v-p-MAX)!=0 ; v++){
// la condición resta el puntero original del temporario y el tamaño del vector
printf("v:%p p:%p %p\n",v,p,(v-p));
//muestra las direcciones de v y p y la diferencia entre ellas
//para un entero y la aritmética de punteros
if (*v>max) max=*v;
}
return max;
}
void main(void){
cout<<"el maximo de vec es:”<<max(vec);
}
Yatay 240 - Buenos Aires - República Argentina
72 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
APENDICE Manejo de archivos
Ejemplos de Archivos en lenguaje C
// Copia de un archivo a otro utilizando fgetc y fputc read y write y los argumentos de la línea de comando
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
int main(int argc, char *argv[]){
int c;
FILE *e, *s;
clrscr();
switch (argc){
case 1:
break;
case 2:
puts("falta el nombre del archivo de entrada y de salida");
exit(1);
puts("falta el nombre del archivo de salida");
exit(1);
break;
}
if ((e=fopen(argv[1],"rb"))==NULL){
puts("error al abrir archivo de entrada");
return 1;
}
if ((s=fopen(argv[2],"wb"))==NULL){
puts("error al abrir archivo de salida");
return 1;
}
while ((c=fgetc(e))!=EOF){ // lee del archivo de entrada un char
fputc(c,s); // copia el char al archivo de salida
}
fclose(e); //cierra el archivo de entrada
fclose(s); // cierra el archivo de salida
return 0;
}
Yatay 240 - Buenos Aires - República Argentina
73 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
version con fread y fwrite
#include <stdio.h>
#include <stdlib.h>
int main(int argc , char *argv[]){
char buffer[1024];
// buffer de lectura y grabación
int bytes;
// cantidad real de bytes leídos
FILE *forigen, *fdestino; // punteros de archivos de origen y destino
//* Comprueba que esta nombres de el origen y destino
if (argc<1) {
cout<<"\n falta nombre de archivo origen y destino";
return 1;
}
if (argc<2) {
cout<<"\n falta nombre archivo destino";
return 1;
}
forigen = fopen(argv[1], "rb"); // se abre como lectura (r) y binario (b)
if(!forigen){
cout<<"\n No se encuentra archivo %s", argv[1];
return 1;
}
fdestino = fopen(argv[2], "rb"); // Comprueba que el destino se puede escribir
if(fdestino){
cout<<"\n El fichero %s ya existe", argv[2];
return 1;
}
fclose(fdestino);
fdestino = fopen(argv[2], "wb"); // se abre como escritura (w) y binario (b)
// Lee 1024 bytes al buffer y luego lo descarga en el destino
if(fdestino){
bytes = fread(buffer, 1, 1024, forigen);
// trata de leer 1024 bytes
// no lleva & delante de buffer por ser una arreglo
// por lo que se pasa el puntero al arreglo buffer y se modifica
while(bytes){ // mientras existan bytes leidos
fwrite(buffer, 1, bytes, fdestino); // graba bytes en destino
bytes = fread(buffer, 1, 1024, forigen);
}
}
fclose(forigen);
fclose(fdestino);
return 0;
}
Yatay 240 - Buenos Aires - República Argentina
74 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Ejemplos de Archivos en lenguaje C++
#include <fstream.h>// ejemplo de archivos en c++ utilizando librería fstream
int main(){
int ch;
ifstream entrada("entrada.dat",ios::in);
// declaro y abro archivo de entrada con el constructor de la clase ifstream
if (!entrada){
cout<<"no se puede abrir archivo";
return 1;
}
ofstream salida;
// declaro variable de archivo
salida.open("salida.dat",ios::out); // abro archivo de salida
if (!salida){
cout<<"no se puede abrir salida";
return 1;
}
while(!entrada.eof()){
entrada.get(ch);
// leo en entrada
salida.put(ch);
// grabo en salida
}
entrada.close();
// cierro archivo
salida.close();
// cierro archivo
return 0;
}
#include <fstream.h>// ejemplo de utilización de un archivo de entrada
#include <iostream.h>
void main(){
char frase[81];
fstream fi; // fi es un objeto de clase archivo
fi.open("d:\\tc\\datos.txt", ios::in); // abre el archivo de entrada con el método open
while(fi.eof()){ // utiliza el metodo eof
fi.getline(frase,20); // lee una linea de 20 de largo con el metodo getline
cout<<frase; // imprime la línea leída
}
fi.close(); // cierra el archivo con el método close
}
#include<iostream.h>//grabación en un archivo de un int un char y un float y su lectura
#include<fstream.h>
#include<conio.h>
int main(){
int i; char c; float f;
ofstream ent("pepe.txt"); // utilizo el constructor para inicializar el objeto ent
if (!ent){ cout<<"error ";return 1;}
else
ent<<100<<"-"<<123.10<<endl;
ent.close();
ifstream sal("pepe.txt");
if (!sal){ cout<<"error ";return 1;}
else{
sal>>i>>c>>f;
cout<<i<<c<<f<<endl;
}
ent.close();}
Yatay 240 - Buenos Aires - República Argentina
75 de 76
V 5.0.0
INSTITUTO de TECNOLOGÍA O. R. T.
Instituto Incorporado a la Enseñanza Oficial (A-763)
Analista de Sistemas de Computación
Taller de Computación III agosto 2008
Errores comunes con punteros y en cadenas de caracteres
(graves abortan el programa, otros programas o bloquean el S.Operativo)
1
int *p;
no inicializar el puntero
*p=10;
2 char *copiar( char *h,char *d){
char * aux;
// no inicializado
while (*d){
*h=*d;
*h++;
*d++;
}
return aux;
debe ir aux=h;
3
falta fin de cadena
*h='\0';
4
devolver puntero que se encuentra al final de la cadena
return h;
5
cad1=cad2 // no copia contenidos no sirve para copiar cadenas ver copymal
6
usar new y no usar delete correspondiente
7
confundir puntero con contenido
while (*d){
h=d;
*h++;
esta demás el* no es lo mismo que(*h)++ ya que cambia el contenido
*d++;
esta demás el *
debería ser d++
}
*h++=*d++;
no es igual a
*++h =*++d
8 confundir el . con ->
uno se utiliza con struct y el otro con puntero
pila.valor con pila->valor
// versión correcta
#include <stdio.h>
char *copiar( char *h,char *d){
char * aux=h;
while (*d){
*h=*d;
h++;
d++;
}
*h='\0';
return aux;
}
void main(){
char cad[80]="hola";
char cad1[80];
copiar(cad1,cad);
puts(cad1);
}
Yatay 240 - Buenos Aires - República Argentina
76 de 76
V 5.0.0
Descargar