Está en la página 1de 212

UNIVERSIDAD CENTRAL DE VENEZUELA

FACULTAD DE CIENCIAS
ESCUELA DE COMPUTACIÓN
Materia: ESTRUCTURA DEL COMPUTADOR

Manual básico de
Programación en C++

Selección: DZ
Índice
(RECOPILACION I)

Diferencias entre C y C++ (1)

Programación orientada a objeto POO

ENCAPSULACIÓN, POLIMORFISMO, HERENCIA

Representación de datos en lenguaje C/C++ (2)

Primer programa en C++

Declaraciones en C++: (2)

Como se declaran variables en C


Como se declaran constantes en C
Reglas de alcance de una variable (3)

signen, unsigned, short, long

Tipo de datos1 (TDD)


Calificadores de tipo
signen, unsigned, short, long
Operador de resolución de alcance unario (4)
(POO) Homonimia de funciones (5)
Comentarios en C/C++
Secuencias de escape en C++
Estructuras condicionales en C (6)
Formas básicas IF-ELSE-ELSE IF
Sentencia CONTINUE, Estructura SWITCH
Como hacer Ciclos en C++ (8)
Tipos de ciclos en C++
Flujo de entrada/salida de C++ (10)
Declaración de archivo de cabecera y su relación con las
Funciones a usar en código fuente
Uso de las sentencias con printf y scanf en C++
Especificadores de formato
Uso de los apuntadores en C 3 (11)
Operadores de Indirección y Dirección “&” y “*”
Instrucción estática->consola: (12)
Ideal para DEV-C++
Cómo crear nuevos tipos de datos en C++
Directivas del Preprocesador Typedef , #include (13)
Arreglos unidimensionales (Vectores)
Llamadas a funciones con arreglos (15)
Arreglos multidimensionales (Matrices)
Registros (17)
Registros y funciones (19)
Arreglos de registros (21)
Definición de tipos (Typedef)

Archivos (22)
Apertura de archivos
Modo texto
Modo binario
Cierre de registros
Escritura y lectura de registros:
Un carácter
Un número entero
Una cadena de caracteres
Con formato (CDT)
Registros (material adicional) (28)
Otras funciones para archivos
Detección de final de archivo
Prototipos de función y verificación de tipo de dato (29)
Operador de resolución de alcance unario
Cómo llamar funciones: parámetros por valor y parámetros por referencia.

(RECOPILACION II)

Resumen sobre las librerías de C++ (31)


Las clases estándar de C++ para entrada/salida
Declaración, apertura y cierre de canales para archivo
Modo Descripción
Como crear clases en C/C++ (32)
Control de acceso a miembros (CDA) (33)
Archivos de cabecera
Declaración de las funciones (34)
Paso de parámetros a una función
Funciones constructoras (35)
Función destructora (36)
¿Cuando son llamados los destructores y constructores?
Asignación por omisión en copia a nivel de miembro en C
Funciones en línea
Verificación de tipos en C++ (37)
¿Cómo poner en práctica un TDA con una clase?
Un código fuente en C++ (40)
Como leer registros
Pase de parámetros por referencia
Variable booleana en un condicional
Nuevo tipo interesante de arreglo en c
Impresión de arreglo…
Librerías9 de C++ (41)
Librería stdio.h

printf , scanf ,puts ,gets ,fopen ,fclose ,fprintf , fgets


Librería tdlib.h

atof , atoi , itoa , exit


Librería conio.h
clrscr,clreol,gotoxy,textcolor,textbackground,wherex,wherey,getch,getche

9 Las funciones de las librerias de C++ dependen del compilador que se este usando lo recomendable es no
usar funciones que otros compiladores no reconoceran si el programa es para otros. Por ejemplo el void
detalle cumple la funcion de gotoxy()

Librería string.h

strlen , strcpy , strcat , strcmp

Funciones interesantes

fflush(stdin),sizeof,cprintf,kbhit,random,randomize,system

Conversión de tipos en C++ (CDT) (44)


Excepciones en C++ (46)
Operaciones con Objetos en C++ (47)
ASIGNACIÓN DE OBJETOS
ARRAY DE OBJETOS (48)
Unidimensional
Bidimensional
DECLARACIÓN, INICIALIZACIÓN
PASO DE OBJETOS A FUNCIONES: (50)
OBJETOS DEVUELTOS POR FUCIONES (51)
PUNTEROS A OBJETOS (52)
Funciones Constructoras y Destructoras (53)
CONSTRUCTORES CON PARAMETROS (56)
Sobrecarga de Funciones y Operadores
Prioridad de operadores en C (ver simplificada) (62)
Funciones inline y Automáticas2 (63)
Utilización de Estructuras como Clases2 (64)
this, new y delete2 (66)
Referencias2 (70)
Herencia2 (71)
Herencia múltiple2 (73)
Funciones Virtuales2 (76)
Funciones Amigas2 (77)
Tipo de dato referencia2 (79)

Apuntadores en C, ¿Por qué son Importantes los Apuntadores?, Operadores de


Indirección y Dirección, Advertencia sobre C, La Aritmética de Apuntadores,
Apuntadores a Funciones, Arreglos en C, ¿Por qué Usar los Arreglos?, La Declaración
de un Arreglo, Breve resumen sobre los arrays, Arreglos y Apuntadores

Apuntadores a Funciones (83)

Punteros a estructuras (88)

Punteros a objetos constantes

Punteros a void (89)


Los operadores NEW Y DELETE (90)

SOBRE ENUMERACIONES, ESTRUCTURAS Y UNIONES EN C++

ENUMERACIONES (91)

ESTRUCTURAS DE ALMACENAMIENTO

UNIONES (92)

CADENAS EN C++ (93)

MAS SOBRE FUNCIONES EN C++

Definición de funciones (94)

Argumentos por omisión en funciones

Más sobre funciones en línea (inline) (95)

Sobrecarga de funciones (96)

Mas sobre el modificador <const> (97)

Paso de parámetros a funciones


1. Por valor
2. Por dirección
3. Por referencia

Paso de arrays en C (98)

Tamaño de un TDD (El operador: sizeof) (100)

La sentencia nula en C

Prioridad y asociatividad de operadores en C (ver completa) (101)


MÁS SOBRE ENTRADAS Y SALIDAS BÁSICAS EN C

Salida
Uso de flujos para salida de caracteres. (102)
Entrada (103)

Manipuladores de C

Palabras reservadas de C (ver completa) (105)


Laboratorio 4 #1 de C++ UCV (106)
Laboratorio 4 #2 de C++ UCV (112)
Sentencias de salto (120)
Sentencias break, continue, goto
SOBRE ALGUNOS OPERADORES (?,::,) (121)
Los backward_warning.h o warning!! de C/C++ (122)
(Una cuestión para ignorar y ejecutar el programa)
Estructuras de almacenamiento (EDA) (123)
Manejo de EDA y apuntadores
Gestión dinánica de memoria (125)
Constantes de tipo enumeración (128)
Diferencias entre POO y POC (129)
La librería para generar tiempo en C++ time.h
Uso del system(“cls”)
Creación de un objeto en C++ (130)
(Código fuente del void detalle versión final)
Plantilla de menú en C++ (136)
(Código fuente del programa, una forma muy básica P.O.O.)
Recursividad en C++ (139)
Los ciclos “infinitos” de C++ (140)
Sentencias break, continue
Instrucciones inmediatas (141)
if, else, for,..
Paso de punteros a objetos (145)
Por valor y por referencia.
Línea de comandos (148)
Ubicación del programa en la unidad C:
Entrada vs Salida
Archivos
(RECOPILACION III)

Material teórico-practico adicional de programación en C++ 7

Variables vs Apuntadores (149)


Objeto vs Clase (notas)
Aprenda a programar con clases (150)
Definición de una clase
Prototipo de clases
Objetos de clases
Funciones miembro
Tipos de funciones miembro
Funciones en línea y fuera de línea
La palabra reservada inline
Archivos de cabecera y de clases
Constructores (160)
Constructor por defecto
Constructores sobrecargados
Constructor de copia
Inicialización de miembros en constructores
Destructores (165)
Clases compuestas (166)
Sobrecarga de funciones polimorfismo
Errores de programación frecuentes en POO
Plantillas de funciones (templates)
Visibilidad de una función (171)
Variables estáticas y automáticas (174)
Compilación separada (176)
Parámetro const de una función (180)
Argumentos por omisión
Detalles de programación básica I (184)
Resumen de la programación con clases (191)
Errores de programación frecuente en POO con clases (193)
Mas sobre el goto, ciclos.
Conclusiones (199)
Programación
Bibliografía consultada (200)
Programación adicional (201,…)
1En muchas sintaxis el TDD se coloca simplemente como <tipo>, <valor_devuelto>. Una función
en cualquier lenguaje de programación, también se puede llamar como un: “tipo operador”.

2 EstudiarOperaciones con Objetos, éstos capítulos corresponden más a la programación


dinámica (abstracta) en C++, mientras que el Manual Básico de Programación en C++, (antes del
apéndice) de programación en C++ va más ligada a programación estructurada.

3En pseudoformal el ” *” se suela cambiar por “^” por lo general y se coloca delante de la
variable, Sintaxis: <nombre_apuntador>^.

4Seagregaron estos laboratorios, tal cual se publicaron el la pagina de la Facultad de Ciencias


UCV contienen muy buena información.

7Para los siguientes tópicos se recomienda revisar los contenidos de el libro Algoritmos,
estructuras de datos y objetos L. Joyanes Aguilar, paj 141 para saber mas acerca las librerías,
funciones y variables de C++ se pretendió abarcar los aspectos mas relevantes de los capítulos
2,3,6, PARTE II de la obra.

*Fuentes usadas: (Total 200 paginas exactas de información y + de ñapa!)

Charter BT (Inserción de algunos signos especiales),

Verdana (texto teoría)

Courier New (código fuente)

Time New Roman (palabras reservadas)


Diferencias entre C y C++

Aunque C++ es un súper conjunto de C, existen algunas diferencias entre los


dos. En primer lugar, en C cuando una función no toma parámetros, su prototipo tiene
la palabra void. Sin embargo en C++ void no es necesario (opcional).

Prototipo en C: char f1(void);


Prototipo en C++: char f1();

Otra diferencia entre C y C++ es que en un programa de C++ todas las


funciones deben estar en forma de prototipo, en C los prototipos se recomiendan, pero
son opcionales. También si una función de C++ es declarada para devolver un valor
obligatoriamente la sentencia return debe devolver un valor, en C no es necesario que
se devuelva.

Otra diferencia es el lugar donde se declaran las variables locales. En C, deben


ser declaradas solo al principio del bloque, mientras que en C++ las variables se
pueden declarar en cualquier punto. Aunque es conveniente realizarlo siempre al
comienzo de la función.

La programación orientada a objetos (POO), permite descomponer un


problema en subgrupos relacionados (método: divide y vencerás). Cada subgrupo pasa
a ser un objeto auto contenido que contiene sus propias instrucciones y datos que le
relacionan con ese objeto. Todos los lenguajes POO comparten tres características:
Encapsulación, Polimorfismo y Herencia.

ENCAPSULACIÓN: Es el mecanismo que agrupa el código y los datos que


maneja. Los mantienen protegidos frente a cualquier interferencia y mal uso. Cuando
el código y los datos están enlazados de esta manera se ha creado un objeto. Ese
código y datos pueden ser privados para ese objeto o públicos para otras partes del
programa.

POLIMORFISMO: Es la cualidad que permite que un nombre se utilice para


dos o más propósitos relacionados pero técnicamente diferentes. El propósito es poder
usar un nombre para especificar una clase general de acciones. Por ejemplo en C
tenemos tres funciones distintas para devolver el valor absoluto. Sin embargo en C++
incorpora Polimorfismo y a cada función se puede llamar abs(). El Polimorfismo se
puede aplicar tanto a funciones como a operadores.

HERENCIA: Proceso mediante el cual un objeto puede adquirir las propiedades


de otro objeto. La información se hace manejable gracias a la clasificación jerárquica.

OBJETO: Conjunto de variables y funciones pertenecientes a una clase


encapsulados. A este encapsulamiento es al que se denomina objeto. Por tanto la clase
es quien define las características y funcionamiento del objeto.

“Todo programa hecho en C puede correr en C++, pero no todos los programas
hechos en C++ corren en C, para empezar abría que cambia su extensión de .cpp a .c”

(1)
Representación de datos en lenguaje C/C++

Estructura básica de un lenguaje en C++: (shell)

(1) //Se hace la importación de librerías


(2) #include <stdio.h> // pueden invocarse mas de una
(3)
(4) //Declaración de variables globales
(5) int z=0; //variable
(6) const float pi2 = 2*3.141592; //constante
(7) int main ()
(8) {
(9) int x=0,y=0; //variables locales a main
(10) //bloque de instrucciones . . .
(11) //creación de constructores opcionales
(12) y=funcion (x,y);
(13) /*instrucción estática->consola se usa con algunos
(14) programas dev C++ por ejemplo*/
(15) return 0; //la función se puede comportar como una (cont.)
(16)} // acción también en C++
(17) int funcion (int &x,int y)
(18) {
(19) int c=0; //variables local a función
(20) c=y; //bloque de instrucciones
(21) return c;
(22) }
(23) //una línea vacía a veces es necesaria al final del código
(24) /*a veces los cuerpos de funciones hay que declararlas arriba
(25) va del cuerpo del main() para que el programa las reconozca
(26) (DEV C++ ó C++) */

Declaraciones en C:
Las declaraciones de variables o funciones pueden ser colocadas antes de
cualquier enunciado ejecutable, siempre y cuando las declaraciones antecedan el uso
de lo que se está declarando.

Como se declaran variables en C:


Se declaran siguiendo el patrón (sintaxis):

<tipo> <nombre>;

Como se declaran constantes en C:

Existen dos tipos de constantes:


-Constantes simbólicas: son las que permiten al programador ponerle un
nombre a una constante y utilizarlo a todo lo largo del programa.

Se declaran siguiendo el patrón (sintaxis):

#define <identificador> <valor>;

(2)
-Otra manera de declarar constantes en C es mediante la palabra reservada
const .
Este calificador permite especificar que un argumento pasado a una función no
es modificable en dicha función o declarar “variables constantes”, en vez de declarar
constantes simbólicas en el preprocesador con #define).

const <tipodedato><identificador> =<valor>;

Es posible inicializar y declarar más de una variable del mismo tipo en la


misma sentencia:

El calificador const se usa en la lista de parámetro de una función para


especificar que un argumento pasado a la función no es modificable en dicha función.
También puede ser utilizado para declarar un apuntador constante.

Creación un apuntador constante a tipo.

<tipodedato> *const <identificador>=<valor>;

(Variable) Apuntador a la constante tipo.

const <tipodedato> *<identificador>=<valor>;

Apuntador constante a tipo constante:

const <tipodedato> *const <identificador> = <valor>;

Reglas de alcance de una variable


El alcance de un identificador o variable es la porción del programa en el cual
dicho identificador puede ser referenciado. Cuando declaramos una variable local en un
bloque, esta puede ser referenciada solamente en dicho bloque o en los bloques
anidados dentro de dicho bloque.

<tipo> <nombre1>=<valor>,<nombre2>=<valor>,<nombre3>=<valor>;

Tipo de datos:

Tipo Tamaño Rango de valores


char 1 byte -128 a 127
int 2 bytes -32768 a 32767
float 4 bytes 3'4 E-38 a 3'4 E+38
double 8 bytes 1'7 E-308 a 1'7 E+308

(3)
Calificadores de tipo

Los calificadores de tipo tienen la misión de modificar el rango de valores de un


determinado tipo de variable. Estos calificadores son cuatro:

· Signen: Le indica a la variable que va a llevar signo. Es el utilizado por defecto.

Tamaño Rango de valores


signed char 1 byte -128 a 127
signed int 2 bytes -32768 a 32767

· Unsigned: Le indica a la variable que no va a llevar signo (valor absoluto).

Tamaño Rango de valores


unsigned char 1 byte 0 a 255
unsigned int 2 bytes 0 a 65535

· Short: Rango de valores en formato corto (limitado). Es el utilizado por


defecto.

Tamaño Rango de valores


short char 1 byte -128 a 127
short int 2 bytes -32768 a 32767

· Long: Rango de valores en formato largo (ampliado).

Tamaño Rango de valores


long char 4 bytes -2.147.483.648 a 2.147.483.647
long int 10 bytes -3'36 E-4932 a 1'18 E+4932

Operador de resolución de alcance unario

Es posible declarar variables locales y globales con un mismo nombre. C++


dispone del operador de resolución de alcance unario (::) para tener acceso a una
variable global cuando está en alcance una variable local con el mismo nombre. No
puede ser utilizado para tener acceso a una variable del mismo nombre en un bloque
externo.
Ejemplo:

#include <iostream.h>
float v;
int main ()
{
int v=7; //se crea una variable entera
::v=10.5 //Utiliza la variable global v
cout<<”variable local v = ”<<v<<”\n”;
cout<<”variable global v = ”<<::v<<”\n”;
return 0;
}

(4)
Homonimia de funciones (Funciones con el mismo nombre)

C++ permite que sean definidas varias funciones del mismo nombre
(sobrecarga de funciones), siempre que estos nombres indiquen distintos conjuntos de
parámetros. Esta capacidad se llama homonimia de funciones. La homonimia de la
función se utiliza por lo común para crear varias funciones del mismo nombre, que
ejecuten tareas similares, sobre tipos de datos distintos.
Las funciones homónimas deben tener distintas listas de parámetros.

La homonimia ayuda a eliminar el uso de las macros #define de C.

/*Definimos dos funciones llamadas max(); una que regrese el mayor de dos
enteros y otra que regrese el mayor de dos string.*/

#include <stdio.h>
int max(int a,int b)
{
if(a>d)
return a;
else
return b;
}
char *max(char *a, char *a)
{
if(strcmp(a,b)>0)
return a;
else
return b;
}
int main()
{
printf(“max(19,69) = %d\n”, max(19,69));
printf(“max(abc,def) = %s\n”, max(“abc”,”def”));
return 0;
}

Comentarios en C/C++

No son tomados en cuenta por el compilador


Comentario de una línea empiezan con // en adelante
Comentario de texto empiezan con /* y terminan con*/

(5)
Secuencias de escape:

Ciertos caracteres no representados gráficamente se pueden representar


mediante lo que se conoce como secuencia de escape. A continuación vemos una tabla
de las más significativas:

\n salto de línea
\b retroceso
\t tabulación horizontal
\v tabulación vertical
\\ contrabarra
\f salto de página
\' apóstrofe
\" comillas dobles
\o fin de una cadena de caracteres

Estructuras condicionales en C:

Estructura IF...ELSE

Sintaxis:

if (<condición>) // if sin llaves equivale a una sola sentencia


<sentencia>; //a ejecutar si se cumple la condición

La sentencia solo se ejecuta si se cumple la condición. En caso contrario el


programa sigue su curso sin ejecutar la sentencia. Otro formato:

Estructura IF...ELSEIF…ELSE

if (<condición_1>)
{ <sentencia_1>;}
else if (<condición_2>)
{ <sentencia_2>;}
else if (<condición_3>)
{ <sentencia_3>;}
else
{ <sentencia_n>; }
/*
Comentario en C observe que también un if puede también no llevar llaves
en cuyo caso estaría ejecutando una instrucción inmediata…
*/

Sentencia CONTINUE

Se utiliza dentro de un bucle. Cuando el programa llega a una sentencia


CONTINUE no ejecuta las líneas de código que hay a continuación y salta a la
siguiente iteración del bucle. Existe otra sentencia, GOTO, que permite al programa
saltar hacia un punto identificado con una etiqueta, pero el buen programador debe
prescindir de su utilización. Es una sentencia muy mal vista en la programación en C.
(6)
Ejemplo:

/* Uso de la sentencia CONTINUE */

#include <stdio.h>

main()
{
int numero=1;
while(numero<=100)
{
if (numero==25)
{
numero++;
continue;
}
printf("%d\n",numero);
numero++;
}
}

Estructura SWITCH

Esta estructura se suele utilizar en los menús, de manera que según la opción
seleccionada se ejecuten una serie de sentencias.

Su sintaxis es:

switch (<variable>)
{
case <contenido_variable1>:
<sentencias_1>;
break;
case <contenido_variable2>:
<sentencias_n-1>;
break;
default:
<sentencias_n>;

break;
}

(7)
/* Uso de la sentencia condicional SWITCH. */

#include <stdio.h>
/*ejemplo de como hacer un switch*/
main()
{
int dia;
printf("Introduce el día: ");
scanf("%d", &dia);

switch(dia){
case 1: printf("Lunes"); break;
case 2: printf("Martes"); break;
case 3: printf("Miércoles"); break;
case 4: printf("Jueves"); break;
case 5: printf("Viernes"); break;
case 6: printf("Sábado"); break;
case 7: printf("Domingo"); break;
default: printf(“Día incorrecto”); break;
}
}

Cada case puede incluir una o más sentencias sin necesidad de ir entre llaves, ya
que se ejecutan todas hasta que se encuentra la sentencia BREAK. La variable
evaluada sólo puede ser de tipo entero o caracter. default ejecutará las sentencias
que incluya, en caso de que la opción escogida no exista.

Como hacer Ciclos en C:

Estructura DO...WHILE

Su sintaxis es:

Do
{
<sentencia1>;
<sentencia2>;
}while (<condición>);

(8)
Ejemplo:

/* Uso de la sentencia DO...WHILE para hacer un menú*/

#include <stdio.h>

main()
{
char seleccion;

do{
printf("1.- Comenzar\n");
printf("2.- Abrir\n");
printf("3.- Grabar\n");
printf("4.- Salir\n");
printf("Escoge una opción: ");
seleccion = getchar(); /*función que lee un caracter*/

switch(seleccion){
case '1':printf("Opción 1");
break;
case '2':printf("Opción 2");
break;
case '3':printf("Opción 3");
}

}while(seleccion!='4');
}

Estructura FOR

Su sintaxis es:

for (<inicialización>;<condición>;<incremento>)
{
<sentencia1>;
<sentencia2>;
}

El flujo del bucle FOR transcurre de la siguiente forma:

(9)
Estructura WHILE

Su sintaxis es:

while(<condicion>)
{
<Sentencia1>;
<Sentencia2>;
}

Flujo de entrada/salida de C++

C++ ofrece una alternativa a las llamadas de función printf y scanf para
manejar la entrada/salida de los tipos y cadenas de datos estándar. Así. En lugar de
printf usamos el flujo de entrada de salida cout y el operador <<(“colocar en”); y en
lugar de scanf usamos el flujo de entrada estandar cin y el operador >>(“obtener
de”) operadores de inserción y extracción de flujo, a diferencia de printf y scanf, no
requiere cadena de formato y de especificadores de conversión( especificadores de
formato) para indicar los tipos de datos que son extraídos o introducidos.

Para utilizar entradas/salidas de flujo, se debe incluir el archivo de cabecera


iostream.h.

Uso de las sentencias printf y scanf

Sentencia printf ( )

La rutina printf permite la aparición de valores numéricos, caracteres y cadenas


de texto por pantalla. El prototipo de la sentencia printf es el siguiente:

printf(<control>,<arg1>,<arg2>...);

Sentencia scanf ( )

La rutina scanf permite entrar datos en la memoria del ordenador a través del
teclado. El prototipo de la sentencia scanf es el siguiente:

scanf(<control>,<arg1>,<arg2>...);

Suponiendo que arg1 fuera una variable mientras que arg2 fuera un
especificador de formato se puede indicar al computador con que datos va a
trabajar

Tanto la función printf como la función scanf trabajan con especificadores de


formato los cuales son:

(10)
%c Un único carácter
%d Un entero con signo, en base decimal
%u Un entero sin signo, en base decimal
%o Un entero en base octal
%x Un entero en base hexadecimal
%e Un número real en coma flotante, con exponente
%f Un número real en coma flotante, sin exponente
%s Una cadena de caracteres
%p Un puntero o dirección de memoria

El formato aunque no muy usado completo de los modificadores es el siguiente:

% [signo] [longitud] [.precisión] [l/L] conversión

· Signo: indicamos si el valor se ajustará a la izquierda, en cuyo caso


utilizaremos el signo menos, o a la derecha (por defecto).

· Longitud: especifica la longitud máxima del valor que aparece por pantalla. Si la
longitud es menor que el número de dígitos del valor, éste aparecerá ajustado a
la izquierda.

· Precisión: indicamos el número máximo de decimales que tendrá el valor.

· l/L: utilizamos l cuando se trata de una variable de tipo long y L cuando es de


tipo double.

Uso de los apuntadores en C: (Se recomienda consultar el apendice)

.-Un Apuntador es una variable que contiene una dirección de memoria, la


cual corresponderá a un dato o a una variable que contiene el dato. Los apuntadores
también deben de seguir las mismas reglas que se aplican a las demás variables,
deben tener nombre únicos y deben de declararse antes de usarse

Operadores de Indirección y Dirección. Hay 2 operadores que se usan


cuando trabajan con direcciones en un programa C; el Operador de Indirección ( * ) y
el de Dirección (&). Estos operadores son diferentes de los tratados anteriormente.

El Operador de Dirección (&) regresa la dirección de una variable. Este


operador está asociado con la variable a su derecha: &h; Esta línea regresa la
dirección de la variable h.

El Operador de Indirección (*) trabaja a la inversa del operador de Dirección.


También esta asociado con la variable a su derecha, toma la dirección y regresa el
dato que contiene esa dirección. Por ejemplo, la siguiente línea determina la dirección
de la variable h y luego usa el operador de Indirección para accesar la variable y darle
un valor de 42.

Ejemplo:

*(&h)=42;

(11)
La declaración de un puntero de manera general es:

Tipo *nombre de apuntador;

Tipo : Especifica el tipo de objeto apuntado y puede ser cualquier tipo.

Nombre de apuntador: Es el identificador del apuntador

Instrucción estática->consola: (ie->c)

En los programas de C algunas veces después de ejecutar el programa la


consola se cierra muy rápido y no permite visualizar en un tiempo razonable el
resultado del programa por consola, entonces es conveniente agregar al final de este
una instrucción de modo que la consola dure un tiempo adecuado abierta esta es:

system("PAUSE");
return EXIT_SUCCESS;
Esta se coloca justo antes de la última llave del main.

Programa estándar hecho en C++

#include <stdlib.h> //libreria de C


#include <iostream>
#include <stdio.h> //libreria de C
#include <cstdlid>
/*variables globales, estructuras, funciones, clases, acciones*/
using namespace std; // (ie->c)
main(int argc, char *argc) // main() en C/C++ da igual
{
/*todo el bloque del programa*/
system("PAUSE"); // (ie->c)
return EXIT_SUCCESS; //puede no ser necesaria aveces(ie->c)
}
/*se hace un enter después de la ultima llave para indicar un
“separador” al compilador de C++, en la mayoría de los casos, si el
programa se hace en lenguaje C++ el cuerpo de las funciones se
declaran arriba del cuerpo del main() desde donde son llamadas*/

Cómo crear nuevos tipos de datos en C++

C++ proporciona la capacidad de crear nuevos tipos definidos por el usuario


mediante el uso de la palabra reservada enum, la palabra reservada struct, la palabra
reservada union y la palabra reservada class.
Por ejemplo, las enumeraciones en C++ son declaradas mediante la palabra
enum y se convierte en un tipo de dato nuevo. Luego, para declarar una variable del
nuevo tipo de dato ya no es necesaria la palabra reservada enum, sino que se utiliza
directamente el nombre del nuevo tipo de dato.

Ejemplo:
enum boolean {FALSE, TRUE};
struct Nombre {char primer [10];char segundo[10];};
(12)
Directivas del Preprocesador-> typedef

La palabra reservada typedef proporciona un mecanismo para la creación de


sinónimos o alias para tipos de datos anteriormente definidos. Al crear un nuevo
nombre utilizando typedef no se crea un nuevo tipo; typedef simplemente crea un
nuevo nombre de tipo que puede ser utilizado como un seudónimo para un nombre de
tipo ya existente, lo cual ayuda a autodocumentar el programa.

Ejemplo:

typedef int IntArray10 [10];

La directiva del preprocesador-> #include

La directiva del preprocesador #include permite que se incluya una copia del
archivo especificado. Las dos formas de la directiva son:

#include <filename>
#include “filename”

La diferencia entre estas formas estriba en la localización donde el preprocesador


buscará el archivo a incluirse. Si el nombre del archivo está encerrado entre comillas,
el preprocesador buscará el archivo en el mismo directorio que el archivo que se está
compilando (este método se utiliza normalmente para incluir archivos de cabecera
definidos por el programador). Si el nombre del archivo está encerrado entre corchetes
angulares (< y >) la búsqueda se llevará a cabo en los directorios predesignados (por
ejemplo cuando se incluyen los archivos de cabecera de la biblioteca estándar).

Arreglos unidimensionales (Vectores)

Un vector es un arreglo unidimensional, es decir, sólo utiliza un índice para


referenciar a cada uno de los elementos. Su declaración será:

<tipo> <nombre> [<tamaño>]; //tamaño es una variable por decir “x”

El tipo puede ser cualquiera de los ya conocidos y el tamaño indica el número


de elementos del vector (se debe indicar entre corchetes [ ]). En el ejemplo se puede
observar que la variable i es utilizada como índice, el primer for sirve para rellenar el
vector y el segundo para visualizarlo. Como se aprecia, las posiciones van de 0 a 9
(total 10 elementos).

Ejemplo:
/* Declaración de un arreglo. */

#include <stdio.h>

main()
{
int vector[10],i;
for (i=0;i<10;i++) vector[i]=i;
for (i=0;i<10;i++) printf(" %d", vector[i]);
}

(13)
Podemos inicializar (asignarle valores) un vector en el momento de
declararlo(igual que en Java). Si lo hacemos así no es necesario indicar el tamaño. Su
sintaxis es:
<tipo> <nombre> []={<valor_1>,<valor_2>,...}
Ejemplos:

int vector[]={1,2,3,4,5,6,7,8};
char vector[]="programador";
char vector[]={'p','r','o','g','r','a','m','a','d','o','r'};

Una particularidad con los vectores de tipo char (cadena de caracteres), es que
deberemos indicar en que elemento se encuentra el fin de la cadena mediante el
caracter nulo (\0). Esto no lo controla el compilador, y tendremos que ser nosotros los
que insertemos este carácter al final de la cadena.

Por tanto, en un vector de 10 elementos de tipo char podremos rellenar un


máximo de 9, es decir, hasta vector[8]. Si sólo rellenamos los 5 primeros, hasta
vector[4], debemos asignar el caracter nulo a vector[5]. Es muy sencillo:
vector[5]='\0';
Ahora veremos un ejemplo de como se rellena un vector de tipo char.

/* Vector de tipo char. */

#include <stdio.h>

main()
{
char cadena[20];
int i;
for (i=0;i<19 && cadena[i-1]!=13;i++)
cadena[i]=getche( );
if (i==19)
cadena[i]='\0';
else
cadena[i-1]='\0';
printf("\n%s",cadena);
}

Podemos ver que en el for se encuentran dos condiciones:

1.- Que no se hayan rellenado todos los elementos (i<19).


2.- Que el usuario no haya pulsado la tecla ENTER, cuyo código ASCII es 13.

También podemos observar una nueva función llamada getche( ), que se


encuentra en conio.h. Esta función permite la entrada de un caracter por teclado.
Después se encuentra un if, que comprueba si se ha rellenado todo el vector. Si es
cierto, coloca el caracter nulo en el elemento 20 (cadena[19]). En caso contrario
tenemos el else, que asigna el caracter nulo al elemento que almacenó el caracter
ENTER.
(14)
En resumen: al declarar una cadena deberemos reservar una posición más que
la longitud que queremos que tenga dicha cadena.

Llamadas a funciones con arreglos

Como ya se comentó en el tema anterior, los arreglos únicamente pueden ser


enviados a una función por referencia. Para ello deberemos enviar la dirección de
memoria del primer elemento del arreglo. Por tanto, el argumento de la función deberá
ser un puntero.

Ejemplo:

/* Envío de un arreglo a una función. */

#include <stdio.h>

void visualizar(int []); /* prototipo */

main()
{
int array[25],i;
for (i=0;i<25;i++)
{
printf("Elemento nº %d",i+1);
scanf("%d",&array[i]);
}
visualizar(&array[0]);
}

void visualizar(int array[]) /* desarrollo */


{
int i;
for (i=0;i<25;i++) printf("%d",array[i]);
}

En el ejemplo se puede apreciar la forma de enviar un arreglo por referencia. La


función se podía haber declarado de otra manera, aunque funciona exactamente igual:

· declaración o prototipo
void visualizar(int *);

· desarrollo de la función
void visualizar(int *arreglo)

Arreglos multidimensionales (Matrices)

Una matriz es un arreglo multidimensional. Se definen igual que los vectores


excepto que se requiere un índice por cada dimensión.

(15)
Su sintaxis es la siguiente:

<tipo> <nombre> [<tamaño_1>][<tamaño_2>],...,[<tamaño_n>];

Una matriz bidimensional se podría representar gráficamente como una tabla


con filas y columnas. La matriz tridimensional se utiliza, por ejemplo, para trabajos
gráficos con objetos 3D. En el ejemplo puedes ver como se rellena y visualiza una
matriz bidimensional. Se necesitan dos bucles para cada una de las operaciones. Un
bucle controla las filas y otro las columnas.

Ejemplo:

/* Matriz bidimensional. */

#include <stdio.h>

main()
{
int x, i, numeros[3][4];

/* rellenamos la matriz */

for (x=0;x<3;x++)
for (i=0;i<4;i++)
scanf("%d",&numeros[x][i]);

/* visualizamos la matriz */

for (x=0;x<3;x++)
for (i=0;i<4;i++)
printf("%d",numeros[x][i]);
}

Si al declarar una matriz también queremos inicializarla, habrá que tener en


cuenta el orden en el que los valores son asignados a los elementos de la matriz.
Veamos algunos ejemplos:

int numeros[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};

Quedarían asignados de la siguiente manera:

numeros[0][0]=1
numeros[0][1]=2
numeros[0][2]=3
numeros[0][3]=4
numeros[1][0]=5
numeros[1][1]=6
numeros[1][2]=7
numeros[1][3]=8
numeros[2][0]=9
numeros[2][1]=10
numeros[2][2]=11
numeros[2][3]=12 (16)
También se pueden inicializar cadenas de texto:

char dias[7][10]={"lunes","martes", … ,"viernes","sábado","domingo"};

Para referirnos a cada palabra bastaría con el primer índice:

printf("%s",dias[i]);

Registros

Concepto de registro

Un registro es un conjunto de una o más variables, de distinto tipo, agrupadas


bajo un mismo nombre para que su manejo sea más sencillo. Su utilización más
habitual es para la programación de bases de datos, ya que están especialmente
indicadas para el trabajo con registros o fichas.

La sintaxis de su declaración es la siguiente:

struct <nombre_tipo_estructura>
{
<TDD> <nombre_variable1>;
<TDD> <nombre_variable2>;
<TDD> <nombre_variable3>;
};

Donde tipo_estructura es el nombre del nuevo tipo de dato que hemos


creado. Por último, tipo_variable y nombre_variable son las variables que forman
parte del registro. Para definir variables del tipo que acabamos de crear lo podemos
hacer de varias maneras, aunque las dos más utilizadas son éstas:

Una forma de definir el registro es:

struct trabajador
{
char nombre[20];
char apellidos[40];
int edad;
char puesto[10];
};

struct trabajador fijo, temporal;

(17)
Otra forma es:

struct trabajador
{
char nombre[20];
char apellidos[40];
int edad;
char puesto[10];
} fijo, temporal;

En el primer caso declaramos el registro, y en el momento en que necesitamos


las variables, las declaramos. En el segundo las declaramos al mismo tiempo que al
registro. El problema del segundo método es que no podremos declarar más variables
de este tipo a lo largo del programa. Para poder declarar una variable de tipo registro,
el mismo tiene que estar declarado previamente. Se debe declarar antes de la función
main.
El manejo de los registros es muy sencillo, así como el acceso a los campos (o
variables) de estos registros. La forma de acceder a estos campos es la siguiente:

<variable>.<campo>;

Donde variable es el nombre de la variable de tipo registro que hemos creado,


y campo es el nombre de la variable que forma parte del registro. Lo veremos mejor
con un ejemplo basado en el registro definido anteriormente:

temporal.edad = 25;

Lo que estamos haciendo es almacenar el valor 25 en el campo edad de la


variable temporal de tipo trabajador. Otra característica interesante de los registros
es que permiten pasar el contenido de un registro a otro, siempre que sean del mismo
tipo naturalmente: (Véase: “Operaciones con Objetos en C++”, paj. 47)

fijo=temporal;

Al igual que con los otros tipos de datos, también es posible inicializar variables
de tipo registro en el momento de su declaración:

struct trabajador fijo={"Pedro","Hernández Suárez", 32, "gerente"};

Si uno de los campos del registro es un arreglo de números, los valores de la


inicialización deberán ir entre llaves:

struct notas
{
char nombre[30];
int notas[5];
};

struct notas alumno={"Carlos Pérez",{8,7,9,6,10}};

(18)
Registros y funciones

Podemos enviar un registro a una función de las dos maneras conocidas:

1.- Por valor: su declaración sería:


void visualizar(struct trabajador);

Después declararíamos la variable fijo y su llamada sería:

visualizar(fijo);

Por último, el desarrollo de la función sería:

void visualizar(struct trabajador datos)

Ejemplo:

/* Paso de un registro por valor. */

#include <stdio.h>

struct trabajador
{
char nombre[20];
char apellidos[40];
int edad;
char puesto[10];
};

void visualizar(struct trabajador);


main()
{
struct trabajador fijo;
printf("Nombre: ");
scanf("%s",fijo.nombre);
printf("\nApellidos: ");
scanf("%s",fijo.apellidos);
printf("\nEdad: ");
scanf("%d",&fijo.edad);
printf("\nPuesto: ");
scanf("%s",fijo.puesto);
visualizar(fijo);
}

void visualizar(struct trabajador datos)


{
printf("Nombre: %s",datos.nombre);
printf("\nApellidos: %s",datos.apellidos);
printf("\nEdad: %d",datos.edad);
printf("\nPuesto: %s",datos.puesto);
}

(19)
2.- Por referencia: su declaración sería:

void visualizar(struct trabajador*);

Después declararemos la variable fijo y su llamada será:

visualizar (&fijo);

Por último, el desarrollo de la función será:

void visualizar(struct trabajador *datos)

Fíjense que en la función visualizar, el acceso a los campos de la variable


datos se realiza mediante el operador ->, ya que lo tratamos con un puntero. En
estos casos siempre utilizaremos el operador ->. Se consigue con el signo menos
seguido de mayor que.

Ejemplo:

/* Paso de un registro por referencia. */

#include <stdio.h>

struct trabajador
{
char nombre[20];
char apellidos[40];
int edad;
char puesto[10];
};

void visualizar(struct trabajador *);


main()
{
struct trabajador fijo;
printf("Nombre: ");
scanf("%s",fijo.nombre);
printf("\nApellidos: ");
scanf("%s",fijo.apellidos);
printf("\nEdad: ");
scanf("%d",&fijo.edad);
printf("\nPuesto: ");
scanf("%s",fijo.puesto);
visualizar(&fijo);
}

void visualizar(struct trabajador *datos)


{
printf("Nombre: %s",datos->nombre);
printf("\nApellidos: %s",datos->apellidos);
printf("\nEdad: %d",datos->edad);
printf("\nPuesto: %s",datos->puesto);}

(20)
Arreglos de registros

Es posible agrupar un conjunto de elementos de tipo registro en un arreglo.


Esto se conoce como arreglo de registros:

struct trabajador
{
char nombre[20];
char apellidos[40];
int edad;
};

struct trabajador fijo[20];

Así podremos almacenar los datos de 20 trabajadores. Ejemplos sobre como


acceder a los campos y sus elementos: para ver el nombre del cuarto trabajador,
fijo[3].nombre;. Para ver la tercera letra del nombre del cuarto trabajador,
fijo[3].nombre[2];. Para inicializar la variable en el momento de declararla lo
haremos de esta manera:

struct trabajador fijo[20] = { {"José", "Herrero Martínez", 29 }, {


"Luis", "García Sánchez", 46 } };

Definición de tipos

El lenguaje 'C' dispone de una declaración llamada typedef que permite la


creación de nuevos tipos de datos. Ejemplos:

typedef int entero; /*acabamos de crear un tipo de dato llamado


entero*/
entero a, b = 3; /*declaramos dos variables de este tipo*/

Su empleo con registros está especialmente indicado. Se puede hacer de varias


formas:

Una forma de hacerlo:

struct trabajador
{
char nombre[20];
char apellidos[40];
int edad;
};

typedef struct trabajador datos;


datos fijo, temporal;

(21)
Otra forma:

typedef struct
{
char nombre[20];
char apellidos[40];
int edad;
}trabajador datos;

datos fijo, temporal;

Archivos

Por último veremos la forma de almacenar datos que podremos recuperar


cuando deseemos. Estudiaremos los distintos modos en que podemos abrir un archivo,
así como las funciones para leer y escribir en él.

Apertura de archivos

Antes de abrir un archivo necesitamos declarar un puntero de tipo FILE, con el


que trabajaremos durante todo el proceso. Para abrir el archivo utilizaremos la función
fopen().

Su sintaxis es:

FILE *<nombre_del_puntero>;
puntero = fopen (<nombre del archivo>, "<modo de apertura>" );

Donde puntero es la variable de tipo FILE, nombre del archivo es el nombre


que daremos al archivo que queremos crear o abrir. Este nombre debe ir encerrado
entre comillas. También podemos especificar la ruta donde se encuentra o utilizar un
arreglo que contenga el nombre del archivo (en este caso no se pondrán las comillas).

Algunos ejemplos:

puntero = fopen("DATOS.DAT","r");
puntero = fopen("C:\\TXT\\SALUDO.TXT","w");

Un archivo puede ser abierto en dos modos diferentes, en modo texto o en


modo binario. A continuación lo veremos con más detalle.

Modo texto

w crea un archivo de escritura. Si ya existe lo crea de nuevo.


w+ crea un archivo de lectura y escritura. Si ya existe lo crea de nuevo.
a abre o crea un archivo para añadir datos al final del mismo.
a+ abre o crea un archivo para leer y añadir datos al final del mismo.
r abre un archivo de lectura.
r+ abre un archivo de lectura y escritura.

(22)
Modo binario

wb crea un archivo de escritura. Si ya existe lo crea de nuevo.


w+b crea un archivo de lectura y escritura. Si ya existe lo crea de nuevo.
ab abre o crea un archivo para añadir datos al final del mismo.
a+b abre o crea un archivo para leer y añadir datos al final del mismo.
rb abre un archivo de lectura.
r+b abre un archivo de lectura y escritura.

La función fopen devuelve, como ya hemos visto, un puntero de tipo FILE. Si


al intentar abrir el archivo se produjese un error (por ejemplo si no existe y lo estamos
abriendo en modo lectura), la función fopen devolvería NULL. Por esta razón es mejor
controlar las posibles causas de error a la hora de programar.

Un ejemplo:

FILE *pf;
pf=fopen("datos.txt","r");
if (pf == NULL) printf("Error al abrir el archivo");

La función freopen cierra el archivo apuntado por el puntero y reasigna este


puntero a un archivo que será abierto.

Su sintaxis es:

freopen(<nombre del archivo>,"<modo de apertura>",<nomb_puntero>);

Donde nombre del archivo es el nombre del nuevo archivo que queremos
abrir, luego el modo de apertura, y finalmente el puntero que va a ser reasignado.

Cierre de registros

Una vez que hemos acabado nuestro trabajo con un archivo es recomendable
cerrarlo. Los archivos se cierran al finalizar el programa pero el número de estos que
pueden estar abiertos es limitado. Para cerrar los archivos utilizaremos la función
fclose();.

Esta función cierra el archivo, cuyo puntero le indicamos como parámetro. Si el


archivo se cierra con éxito devuelve 0.

fclose(<nomb_puntero>);

Un ejemplo ilustrativo es:

FILE *pf;
pf = fopen("AGENDA.DAT","rb");
if ( pf == NULL )
printf ("Error al abrir el archivo");
else
fclose(pf);
(23)
Escritura y lectura de registros

A continuación veremos las funciones que se podrán utilizar dependiendo del


dato que queramos escribir y/o leer en el archivo.

Un carácter:

fputc(<variable_caracter>,<puntero_archivo>);

Escribimos un caracter en un archivo (abierto en modo escritura).

Un ejemplo:

FILE *pf;
char letra='a';
if (!(pf=fopen("datos.txt","w"))) /* forma de controlar si hay un
error */
{
printf("Error al abrir el archivo");
exit(0); /* abandonamos el programa */
}
else
fputc(letra,pf);
fclose(pf);

La función fgetc(<puntero_archivo>), lee un caracter de un archivo


(abierto en modo lectura). Deberemos guardarlo en una variable.

Un ejemplo:

FILE *pf;
char letra;
if (!(pf=fopen("datos.txt","r"))) /* controlamos si se produce un
error */
{
printf("Error al abrir el archivo");
exit(0); /* abandonamos el programa */
}
else
{
letra=fgetc(pf);
printf("%c",letra);
fclose(pf);
}

(24)
Un número entero:

putw(<variable_entera>,<puntero_archivo>);

Escribe un número entero en formato binario en el archivo.

Ejemplo:

FILE *pf;
int num=3;
if (!(pf=fopen("datos.txt","wb"))) /* controlamos si se produce un
error */
{
printf("Error al abrir el archivo");
exit(0); /* abandonamos el programa */
}
else
{
fputw(num,pf); /* también podíamos haber hecho:
fputw(3,pf); */
fclose(pf);
}

La función getw( puntero_archivo ), lee un número entero de un archivo,


avanzando dos bytes después de cada lectura.

Un ejemplo:

FILE *pf;
int num;
if (!(pf=fopen("datos.txt","rb"))) /* controlamos si se produce un
error */
{
printf("Error al abrir el archivo");
exit(0); /* abandonamos el programa */
}
else
{
num=getw(pf);
printf("%d",num);
fclose(pf);
}

(25)
Una cadena de caracteres:

fputs(<variable_array>,<puntero_archivo>);

Escribe una cadena de caracteres en el archivo.


Ejemplo:

FILE *pf;
char cad="Me llamo Vicente";
if (!(pf=fopen("datos.txt","w")))
/* controlamos si se produce un error */
{
printf("Error al abrir el archivo");
exit(0); /* abandonamos el programa */
}
else
{
fputs(cad,pf);
/* o también así: fputs("Me llamo Vicente",pf); */
fclose(pf);
}

La función fgets( variable_array, variable_entera, puntero_archivo ), lee


una cadena de caracteres del archivo y la almacena en variable_array. La
variable_entera indica la longitud máxima de caracteres que puede leer.

Un ejemplo:

FILE *pf;
char cad[80];
if (!(pf=fopen("datos.txt","rb")))
/* controlamos si se produce un error */
{
printf("Error al abrir el archivo");
exit(0); /* abandonamos el programa */
}
else
{
fgets(cad,80,pf);
printf("%s",cad);
fclose(pf);
}

(26)
Con formato:

fprintf(<puntero_archivo>,<formato>,<argumentos>);

Funciona igual que un printf pero guarda la salida en un archivo.

Ejemplo:

FILE *pf;
char nombre[20]="Santiago";
int edad=34;
if (!(pf=fopen("datos.txt","w")))
/* controlamos si se produce un error */
{
printf("Error al abrir el archivo");
exit(0); /* abandonamos el programa */
}
else
{
fprintf(pf,"%20s%2d\n",nombre,edad);
fclose(pf);
}

La función fscanf(<puntero_archivo>,<formato>,<argumentos>), lee


los argumentos del archivo. Al igual que con un scanf, deberemos indicar la dirección
de memoria de los argumentos con el símbolo & ( ampersand ).

Un ejemplo:

FILE *pf;
char nombre[20];
int edad;
if (!(pf=fopen("datos.txt","rb")))
/* controlamos si se produce un error */
{
printf("Error al abrir el archivo");
exit(0); /* abandonamos el programa */
}
else
{
fscanf(pf,"%20s%2d\",nombre,&edad);
printf("Nombre: %s Edad: %d",nombre,edad);
fclose(pf);
}

(27)
Registros

fwrite( *buffer,<tamaño>,<nº de veces>,<puntero_archivo>);

Se utiliza para escribir bloques de texto o de datos, registros, en un archivo. En


esta función, *buffer será la dirección de memoria de la cuál se recogerán los datos;
tamaño, el tamaño en bytes que ocupan esos datos y nº de veces, será el número
de elementos del tamaño indicado que se escribirán.

fread( *buffer,<tamaño>,<nº de veces>,<puntero_archivo>);

Se utiliza para leer bloques de texto o de datos de un archivo. En esta función,


*buffer es la dirección de memoria en la que se almacenan los datos; tamaño, el
tamaño en bytes que ocupan esos datos y nº de veces, será el número de elementos
del tamaño indicado que se leerán.

Otras funciones para archivos:

· rewind( <puntero_archivo> ): Sitúa el puntero al principio del archivo.

· fseek(<puntero_archivo>,long <posición>,int <origen>): Sitúa el


puntero en la posicion que le indiquemos. Como origen podremos poner:

· 0 = SEEK_SET, el principio del archivo


· 1 = SEEK_CUR, la posición actual
· 2 = SEEK_END, el final del archivo

· rename(<nombre1>,<nombre2>): Su función es exactamente la misma


que la que conocemos en MS-DOS. Cambia el nombre del archivo nombre1
por un nuevo nombre, nombre2.
·
remove(<nombre>): Como la función del DOS del, podremos eliminar el
archivo indicado en nombre.

Detección de final de archivo

La función feof(<puntero_archivo>), siempre deberemos controlar si


hemos llegado al final de archivo cuando estemos leyendo, de lo contrario podrían
producirse errores de lectura no deseados. Para este fin disponemos de la función
feof(). Esta función retorna 0 si no ha llegado al final, y un valor diferente de 0 si lo
ha alcanzado.

Pues con esto llegamos al final del tema. Espero que no haya sido muy
pesado. No es necesario que te aprendas todas las funciones de memoria. Céntrate
sobre todo en las funciones fputs(), fgets(), fprintf(), fwrite() y fread(). Con
estas cinco se pueden gestionar los archivos perfectamente.

(28)
Prototipos de función y verificación de tipo de dato

Los prototipos de función le permiten al compilador verificar por tipo la


exactitud de las llamadas de función. En C++ los prototipos de función son requeridos
para todas las funciones. Sin embargo, una función definida en un archivo, antes de
cualquier llamada a la misma, no requiere de un prototipo de función, ya que el
encabezado de función actúa como tal. Todos los parámetros de la función deberán
declararse entre los paréntesis del prototipo y de la definición de función. En caso que
no existan parámetros, bastará con colocar paréntesis vacíos.

Ejemplo:

int potencia (int, int);

Operador de resolución de alcance unario

Es posible declarar variables locales y globales con un mismo nombre. El


operador de resolución de alcance unario (::) permite tener acceso a una variable
global cuando está en alcance una variable local con el mismo nombre. El operador de
resolución de alcance unario no puede ser utilizado para tener acceso a una variable
con el mismo nombre en un bloque externo. Se puede tener acceso a una variable
global de forma directa, sin usar el operador de resolución de alcance unario,
siempre que no exista una variable local en alcance con el mismo nombre.

Cómo llamar funciones: parámetros por valor y parámetros por


referencia.
Cuándo los argumentos se pasan en una llamada de una función por valor se
efectúa una copia del valor del argumento y este se pasa a la función llamada. Las
modificaciones a la copia no afectarán el valor original de la variable del llamador.
Cuando un argumento es pasado por referencia, el compilador pasa la dirección de
memoria del valor del parámetro a la función. Cuando se modifica el valor del
parámetro (la variable local), este valor queda almacenado en la misma dirección de
memoria, por lo que al retornar a la función llamadora la dirección de memoria donde
se almacenó el parámetro contendrá el valor modificado. Para declarar una variable
parámetro como paso por referencia, el símbolo & debe preceder al nombre de la
variable. Por ejemplo la función de intercambio, que intercambia los valores de dos
variables:

void intercambio ( int &a, int &b)


{
int aux = a;
a = b;
b = aux;
}

Los parámetros a y b son parámetros por referencia. Por consiguiente, cualquier


cambio efectuado en el interior de la función se transmitirá al exterior de la misma.
Para llamar a la función intercambio () por referencia, simplemente se pasan las
variables a intercambiar, por ejemplo:

(29)
Ejemplo:

int i = 3, j = 50;
intercambio (i, j);

También un parámetro por referencia es un seudónimo (“alias”) de su


argumento correspondiente. Para indicar que un parámetro de función es pasado por
referencia, solo hay que colocar un ampersand (&) después del tipo del parámetro en
el prototipo de función.

Debemos usar apuntadores para pasar argumentos que pudieran ser


modificados por la función llamada, y usar referencias a constantes para pasar
argumentos extensos que no serán modificados.

Las variables de referencia deben ser inicializadas en sus declaraciones, y no


pueden ser reasignadas como seudónimos a otras variables.

Cuando se regresa un apuntador o una referencia a una variable declarada en la


función llamada, la variable deberá ser declarada static dentro de dicha función.

Las referencias pueden ser usadas como argumentos de funciones y regresar


valores.
Ejemplo:
int ix; // ix es una variable en entera
int &rx=ix; // rx es el “alias” de ix
ix=1; // tambien rx ==1
rx=2; // tambien ix==2

Las referencias se pueden usar para proveer una función con un alias de un
argumento real de llamada de función. Este permite cambiar el valor del argumento de
llamada de función tal como se conoce de otros lenguajes de programación de llamada
por referencia:

/*U se pasa por valor y S por referencia*/

void mira (int U, int &S)


{
U=42;
S=42;
}
void mar()
{
int U,S;
U=S=1; //inicializacion en una linea
mirar(U,S);
//en este punto S=42 y U=1;
}

(30)
Resumen sobre las librerías de C

Las clases estándar de C++ para entrada/salida

Las primeras versiones de C++ desarrolladas en 1980 por Bjarne Stroustrup se


basaban en el sistema de entrada y salida de su lenguaje padre C. Aunque todavía se
puede usar en C++ a través de la librería <cstdio>, nos centraremos en cambio en el
sistema de E/S basado en canales, estas son las clases de la librería <iostream>.

Declaración, apertura y cierre de canales para archivo

Para que un programa pueda leer o escribir valores de un archivo de texto,


debe construir un objeto ifstream o ofstream, respectivamente.

ifstream canal_entrada;
ofstream canal_salida;

Estas instrucciones declaran los objetos canal_entrada y canal_salida como


canales de archivo sin inicializar –como conexiones potenciales entre el programa y los
archivos-. Se convierten en conexiones reales cuando se envía un mensaje open():

canal_entrada.open(“nombre_archivo_texto_entrada”);
canal_salida.open(“nombre_archivo_texto_salida”);

Estos dos pasos –declarar y abrir- se pueden combinar usando declaraciones de


inicialización:

ifstream canal_entrada(“nombre_archivo_texto_entrada”);
ofstream canal_salida(“nombre_archivo_texto_salida”);

Por defecto la apertura de un ofstream hacia un archivo es destructiva, es


decir, si el archivo existe, su contenido es destruido. Para evitar esto, se puede enviar
un mensaje de open() con un segundo argumento de modo, que puede ser cualquiera
de los siguientes:

Modo Descripción

ios::in Es el modo por defecto de los objetos ifstream. Abre un archivo para lectura,
de forma no destructiva, colocándose para leer al principio del archivo.
ios::trunc Abre un archivo y borra su contenido.
ios::out Es el modo por defecto de los objetos ofstream. Abre un archivo para
escritura, usando ios::trunc.
ios::app Abre un archivo para escritura, pero de forma no destructiva, colocándose para
escribir al final del archivo (es decir, para concatenar).
ios::ate Abre un archivo existente colocándose para leer (en los objetos ifstream) o para
escribir (en los objetos ofstream) al final del archivo.

(31)
ios::binary Abre un archivo sobre el que se hará E/S en modo binario en lugar de en modo
texto. Usando read() se leen bytes del archivo y se guardan en arreglos de char, y
usando write() se escriben bytes desde arreglos de char en el archivo.
Al finalizar el tratamiento con el archivo debe romperse la conexión
entre el programa y el archivo enviándole el mensaje close():
canal_entrada.close();
canal_salida.close();

Las clases ifstream, ofstream y fstream son subclases de la clase istream, ostream y
iostream, respectivamente. Por lo tanto, todas las operaciones para E/S interactiva se
pueden usar para E/S a través de fichero. Por ejemplo, una vez que se haya declarado
el objeto canal_entrada de tipo ifstream y se ha conectado a un archivo de texto, se
puede leer un valor de él exactamente de la misma forma que hicimos para la E/S
interactiva:

canal_entrada >> variable;

Como crear clases en C/C++

En C y en otros lenguajes de programación procedurales, la


programación tiende a ser orientada a acción, en tanto que en la
programación C++ tiende a ser orientada al objeto. En C, la unidad de
programación es la función. En C++ es la clase a partir de la cual
eventualmente los objetos son producidos (es decir, son creados). Los
programadores en C++ se concentran en crear sus propios tipos de datos,
conocidos como clases. Para ello, deben definir el formato general utilizando
la palabra reservada class. Cada clase contiene datos junto con un conjunto
de funciones que manipula dichos datos.
Los componentes de datos de una clase se llaman miembros de datos.
Los componentes de función de una clase se llaman funciones miembros. Al
igual que un ejemplo de un tipo incorporado int se conoce como una
variable, un ejemplo de un tipo definido por un usuario (es decir, una clase) se
conoce como un objeto.

class <nombre_clase>
{
// miembros de datos
public: //puede ser private o protected
// funciones / objetos miembros
} // lista_objetos

(32)
Control de acceso a miembros (CDA)

Se utilizan tres especificadores de acceso para controlar el acceso a los


miembros de la clase, estos son: public, private y protected. El especificador public
define miembros públicos, que son aquellos a los que se puede acceder por cualquier
función. A los miembros que siguen al especificador private sólo se puede acceder por
funciones miembro de la misma clase o por funciones y clases amigas. A los miembros
que siguen al especificador protected se puede acceder por funciones miembro de la
misma clase o de clases derivadas de la misma, así como amigas. Los especificadores
public, private y protected pueden aparecer en cualquier orden. Si se omite el
especificador de acceso, el acceso por defecto es privado.

class <nombre_clase>
{
//datos y funciones privadas
public:
//datos y funciones públicas
} //lista_objetos

Una función amigo de una clase se define por fuera del alcance de dicha clase,
pero aún así tiene el derecho de acceso a los miembros private y protected de la clase.
Se puede declarar una función o toda una clase como un friend de otra clase.

Para declarar una función como friend de una clase, en la definición de clase
preceda el prototipo de función con la palabra reservada friend. Para declarar una
clase B como amigo de la clase A entre los miembros de la clase A debe existir la
siguiente declaración:

friend B;

Esto significa que la amistad es concedida y no tomada, es decir, para que la


clase B sea un amigo de la clase A, la clase A debe declarar que la clase B es su amigo.
También la amistad no es ni simétrica ni transitiva, es decir, si la clase A es un amigo
de la clase B, y la clase B es un amigo de la clase C, no es correcto pensar que la clase
B es un amigo de la clase A, que la clase C es un amigo de la clase B , ni que A es un
amigo de la clase C.

Archivos de cabecera

Cada biblioteca estándar tiene su archivo de cabecera correspondiente, que


contiene los prototipos de función de todas las funciones de dicha biblioteca, y las
definiciones de varios tipos de datos y de constantes requeridas por dichas funciones.
Por ejemplo la biblioteca estándar encargada de manipular la hora y fecha, se puede
añadir a nuestro programa incluyendo el archivo de cabecera <time.h> El
programador también puede crear archivos de cabecera para cada una de las clases
que define en su programa. Para ello, el nombre de dicho archivo deberá terminar en
.h y podrá ser incluido utilizando la directriz de preprocesador #include. Este archivo
contendrá los miembros de datos de la clase y los prototipos de las funciones
pertenecientes a dicha clase.
(33)
Declaración de las funciones

Al igual que las variables, las funciones también han de ser declaradas. Esto es
lo que se conoce como prototipo de una función. Para que un programa en C sea
compatible entre distintos compiladores es imprescindible escribir los prototipos de las
funciones.

Los prototipos de las funciones pueden escribirse antes de la función main o


bien en otro archivo. En este último caso se lo indicaremos al compilador mediante la
directiva #include.

En el ejemplo siguiente podremos ver la declaración de una función (prototipo).


Al no recibir ni retornar ningún valor, está declarada como void en ambos lados.
También vemos que existe una variable global llamada num. Esta variable es
reconocible en todas las funciones del programa. Ya en la función main encontramos
una variable local llamada num. Al ser una variable local, ésta tendrá preferencia
sobre la global. Por tanto la función escribirá los números 10 y 5.

Ejemplo:

/* Declaración de funciones. */

#include <stdio.h>

void funcion(void); /* prototipo */


int num = 5; /* variable global */

main()
{
int num=10; /* variable local */
printf("%d\n",num);

funcion(); /* llamada */
}

void funcion(void)
{
printf("%d\n",num);
}

Paso de parámetros a una función

Como ya hemos visto, las funciones pueden retornar un valor. Esto se hace
mediante la instrucción return, que finaliza la ejecución de la función, devolviendo o
no un valor. En una misma función podemos tener más de una instrucción return. La
forma de retornar un valor es la siguiente:

Sintaxis:

return (<valor o expresión>);

(34)
El valor devuelto por la función debe asignarse a una variable. De lo contrario,
el valor se perderá. En el ejemplo puedes ver lo que ocurre si no guardamos el valor
en una variable. Fíjate que a la hora de mostrar el resultado de la suma, en el printf,
también podemos llamar a la función.

Ejemplo:

/* Paso de parámetros. */

#include <stdio.h>

int suma(int,int); /* prototipo */

main()
{
int a = 10, b = 25, t;
t = suma(a, b); /* guardamos el valor */
printf("%d=%d", suma(a, b), t);
suma(a, b); /* el valor se pierde */
}

int suma(int a, int b)


{
return (a + b);
}

Funciones constructoras

Después que los objetos son creados, sus miembros pueden ser inicializados
mediante funciones constructor. Un constructor es una función miembro de clase con
el mismo nombre que la clase. El programador proporciona el constructor que cada vez
que se crea un objeto de dicha clase, es invocado automáticamente. Los miembros de
datos de una clase no pueden ser inicializados en la definición de la clase. Más bien, los
miembros de datos deben ser inicializados en un constructor de la clase o sus valores
definidos más adelante después que el objeto haya sido creado. Los constructores no
pueden especificar tipos de regreso y valores de regreso. Los constructores pueden ser
sujetos de homonimia, para permitir una variedad de maneras de inicializar objetos de
una clase.

Sintaxis:

<nombre_clase> (<lista de parámetros>);

(35)
Función destructora

Un destructor es una función miembro especial de una clase, su nombre está basado
en la tilde (~) seguida por el nombre de la clase. Un destructor de una clase es
llamado automáticamente cuando un objeto de una clase se sale de alcance. De hecho
el destructor mismo no destruye el objeto, más bien ejecuta trabajos de terminación,
antes de que el sistema recupere el espacio de memoria del objeto con el fin de que
pueda ser utilizado para almacenar nuevos objetos. Un destructor no recibe ningún
parámetro, ni regresa ningún valor. Una clase sólo puede tener un destructor – la
homonimia de destructores no está permitida. Sintaxis:

~ <nombre_clase> ();

Ejemplo:

class Punto
{
int _x,_y;
public:
Punto()
{
_x = _y = 0;
}
}
Punto(const int x,const int y)
{
_x = desde._x;
_y = desde._y;
}
Punto(){/*¡Nada que hacer*/}
˜
void setX(const int val);
void setY(const int val);
int getX(){return _x;}
int getY(){return _y;}
};

Cuando son llamados los destructores y constructores:

Por lo general, son llamados de forma automática. En general, las llamadas de


destructor se efectúan en orden inverso a las llamadas del constructor.

Asignación por omisión en copia a nivel de miembro:


Operador de asignación ( = ) es utilizado para asignar un objeto a otro objeto
del mismo tipo.

Funciones en línea:

Existen funciones en línea que ayudan a reducir la carga por llamadas de función
especial para pequeñas funciones .El compilador puede ignorar el calificador inline y
típicamente así lo hará para todo, a excepción de las funciones más pequeñas. El
calificador inline deberá ser utilizado sólo tratándose de funciones pequeñas, de uso
frecuente. Usar funciones inline puede reducir el tiempo de ejecución, pero puede
aumentar el tamaño de programa. (36)
Ejemplo

//Usamos la función inline para calcular el volumen de un


//cubo.

#include <iostream.h>

inline float cubo(const float s){return s*s*s;}

main()
{
cout<<”Introduce la longitud del lado de un cubo: ”
float lado;
cin >>lado;
cout <<”El volumen del lado”;
cout<<volumen<<”es”<<cubo(lado)<<”\n”;
return 0;
}

Verificación de tipos en C++


La verificación o comprobación de tipos en C++ es más rígida (estricta) que en C.
Algunas consideraciones a tener en cuenta son:
Usar funciones declaradas. Esta acción es ilegal en C++, y está permitida en C:
int main()
{
//...
printf(x) //C int printf(x)
//C++ es ilegal, ya que printf no esta declarada
return 0;
}
• Fallo al devolver un valor de una función. Una función en C++ declarada con un tipo
determinado de retomo, ha de devolver un valor de ese tipo. En C, está permitido no seguir la
regla.

• Asignación de punteros void. La asignación de un tipo void* a un puntero de otro tipo se debe
hacer con una conversación explícita en C++. En C, se realiza implícitamente.

• Inicialización de constantes de cadena. En C++ se debe proporcionar un espacio para el


carácter de terminación nulo cuando se inicializan constantes de cadena. En C, se permite la
ausencia de ese carácter
int main()
{
//......
char car[7] = “Cazorla“; // legal en C
//error en C++
//......
return 0;
}
Una solución al problema que funciona tanto en C como en C++ es: char car [] ="Cazorla";

¿Cómo poner en práctica un TDA con una clase?


Las clases permiten que el programador modele objetos que tienen atributos
(miembros de datos) y comportamientos u operadores (funciones miembros). Los tipos
contienen miembros de datos y funciones miembro, y son definidos mediente la
palabra reservada class.
(37)
Ejemplo:

Class Punto //Declaracion de la clase punto


{
int _x,_y; //coordenadas del punto
public: //Principio de la declaración de la interfase.
void setX(const int val);
void setY(const int val);
int getX(){return _x;}
int getY(){return _y;}
}; //fin class
Punto apunto; //Definicion del objeto apunto.

/*El objeto apunto puede usar estos metodos para establecer y para
obtener información sobre sí mismo.*/

apunto.setX(1); //inicializacion
apunto.setY(1);
/*
x es necesaria a partir de aquí, de modo que la definimos aquí y la
inicializamos con el valor de la coordenada _x de apunto.
*/

int x = apunto.getX();

void Punto::setX(const int val) //definimos el método setX


//ámbito de la clase Punto
{
_x = val;
}
void Punto::setY (const int val)
{
_y = val;
}

Comentario
Comenzamos con la definición de una clase, indicándola con la palabra
reservada class. El cuerpo de la definición de clase se delimita mediante llaves. La
definición de clase termina con un punto y coma. En el cuerpo de la definición existen
partes nuevas: la etiqueta public: y private: se conocen como especificadores de
acceso. Cualquier miembro de datos o función miembro declarado después del
especificador de acceso de miembro) es accesible, siempre que el programa tenga
acceso a un objeto de la clase. Cualquier miembro de datos o función miembro
declarada después del especificador de acceso de miembro private: (y hasta el
siguiente especificador de acceso de miembro) sólo es accesible a las funciones
miembro de la clase.

Estos especificadores pueden aparecer varias veces en una definición de clase.


Por defecto, los elementos de las clases son privados ( private: ).
(38)
Por lo regular, los miembros de datos aparecen listados en la porción private:
de una clase, y normalmente, las funciones de miembro aparecen listadas en la
porción public:, aunque pueden darse en caso contrario.

Los miembros de datos de una clase no pueden ser inicializados donde son
declarados en el cuerpo de la clase. Deberán ser inicializados por el constructor de la
clase, o las funciones “ser” les asignar valores.

La función con el mismo nombre que la clase, pero precedido por un carácter
tilde (˜) se llama el destructor de dicha clase.

Cuando una función miembro se define por fuera de la definición de clase, el


nombre de función es antecedido por el nombre de la clase y por el operador de
resolución de alcance binario (::). Dicha función miembro queda dentro del alcance de
la clase.

El objeto apunto puede usar estos metodos para establecer y para obtener
información sobre sí mismo.

(39)
Un programa hecho en C++:

#include <cstdlib>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
int main(int argc, char *argv[])
{
int algo=0; //se declara y valida una variable entera
FILE *f; //se declara un apuntador a un archivo FILE
char b[20]; //en C/C++ el string no existe
f=fopen("archivo.txt","r"); //se habre un archivo
while(!feof(f)){ //mientras no see fin de archivo lee
fgets(b,20,f); //lee linea por línea
printf("%s\n",b); //imprime lo que hay en el archivo.txt
}
system("PAUSE"); // (ie->c)
return 0; //ideal para convertir una funcion en acción
algo=funcionentero(algo); //”algo” es pasado por referencia
/* EL COMPILADOR DE C IGNORA ESTE BLOQUE-------------------------(1)
//creación de arreglos, relleno y escritura
int *x=(int*)malloc(sizeof(int)*20);
for (int h=1;h<21;h++)
{
x[h]=u;
printf("%d",x[h]); //impresión vulgar
u++;
}
algo=funcion(x);
printf("la posicion del arreglo es %d\n",algo);
imprime(x);
*/ //FIN DE UN BLOQUE COMENTADO----------------------------------(2)
int resul=algo&0x01; //resul=((bit_de_paridad_de_algo)&(00000001))
if(resul) //resul vale (0 ó 1) como un booleano “implicito”
{printf("El numero es impar");}
else
{printf("El numero es par");}
} //fin del main()
int funcion(int x[]) //si es un arreglo el que se pasa por parametro
{ //no se le pone el apuntador “&” se pasa por valor
int b=0;
b=x[20];
return b;
}
void imprime(int x[])
{
for(int f=1;f<21;f++)
{
printf("%d",x[f]);
}
}
int funcionentero(int &algo){return algo;} //se pasa por referencia & por lo
//que no modifica el valor de algo
//en el main. Solo se pasa la
//dirección de memoria donde esta
//”algo”, las palabras coloreadas en
//azul y violeta son palabras
//reservadas de C/C++ y se les
//conoce como tokens de C/C++

(40)
Apéndice
En este capítulo y para finalizar veremos los archivos de cabecera, donde
están declaradas las funciones que utilizaremos más a menudo.

Librería stdio.h (Librería estandar de C/C++)

printf
Función: Escribe en la salida estándar con formato.
Sintaxis: printf(<formato>,<arg1>, ...);

scanf
Función: Lee de la salida estándar con formato.
Sintaxis: scanf(<formato>,<arg1>, ...);

puts
Función: Escribe una cadena y salto de línea.
Sintaxis: puts(<cadena>);

gets
Función: Lee y guarda una cadena introducida por teclado.
Sintaxis: gets(<cadena>);

fopen
Función: Abre un fichero en el modo indicado.
Sintaxis: pf=fopen(<fichero> , <modo de apertura>);

fclose
Función: Cierra un fichero cuyo puntero le indicamos.
Sintaxis: fclose(<nombre_puntero>);

fprintf
Función: Escribe con formato en un fichero.
Sintaxis: fprintf(<nombre_puntero> , <formato> , <arg1> , ...);

fgets
Función: Lee una cadena de un fichero.
Sintaxis: fgets(<cadena> , <longitud> , <nombre_puntero>);

Librería stdlib.h (Librería estandar de C/C++)

atof
Función: Convierte una cadena de texto en un valor de tipo float.
Sintaxis: float <nomb_variable> = atof(<cadena>);

atoi
Función: Convierte una cadena de texto en un valor de tipo entero.
Sintaxis: int <nomb_variable>= atoi(<cadena>);

(41)
itoa
Función: Convierte un valor numérico entero en una cadena de texto. La base
generalmente será 10, aunque se puede indicar otra distinta.
Sintaxis: itoa(<número> , <cadena> , <base>);

exit
Función: Termina la ejecución y abandona el programa.
Sintaxis: exit(<variable_estado>); /* Normalmente el estado será 0 */

Librería conio.h (Librería estandar de C/C++)

clrscr
Función: Borra la pantalla.
Sintaxis: clrscr( ); es lo mismo que system(“cls”) ;

clreol
Función: Borra desde la posición del cursor hasta el final de la línea.
Sintaxis: clreol( );

gotoxy
Función: Cambia la posición del cursor a las coordenadas indicadas.
Sintaxis: gotoxy(<columna> , <fila>);

textcolor
Función: Selecciona el color de texto (0 - 15).
Sintaxis: textcolor(<variable_color>);

textbackground
Función: Selecciona el color de fondo (0 - 7).
Sintaxis: textbackground(<variable_color>);

wherex
Función: Retorna la columna en la que se encuentra el cursor.
Sintaxis: <variable_columna>=wherex( );

wherey
Función: Retorna la fila en la que se encuentra el cursor.
Sintaxis: <variable_fila>=wherey( );

getch
Función: Lee y retorna un único caracter introducido mediante el teclado por el
usuario. No muestra el carácter por la pantalla.
Sintaxis: char <nomb_variable> =getch();

getche
Función: Lee y retorna un único carácter introducido mediante el teclado por el
usuario.
Muestra el carácter por la pantalla.
Sintaxis: char <nomb_variable> = getche();

(42)
Librería string.h (Librería estándar de C++)

strlen
Función: Calcula la longitud de una cadena.
Sintaxis: int <nomb_variable>=strlen(<cadena>);

strcpy
Función: Copia el contenido de una cadena sobre otra.
Sintaxis: strcpy(<cadena_a_sobre_escribir>,<cadena_original>);

strcat
Función: Concatena dos cadenas.
Sintaxis: strcat(<cadena_1>,<cadena_2>,…,<cadena_n>);

strcmp
Función: Compara el contenido de dos cadenas. Si cadena1 < cadena2 retorna
un número negativo. Si cadena1 > cadena2, un número positivo, y si cadena1 es
igual que cadena2 retorna 0 ( o NULL ).
Sintaxis: int <nomb_variable>=strcmp(<cadena1>,<cadena2>);

Funciones interesantes

fflush(stdin)
Función: Limpia el buffer de teclado.
Sintaxis: fflush(stdin);
Prototipo: stdio.h

sizeof
Función: Operador que retorna el tamaño en bytes de una variable.
Sintaxis: int <nomb_variable_2>= sizeof (nomb_variable_1|TDD);

cprintf
Función: Funciona como el printf pero escribe en el color que hayamos activado con
la función textcolor sobre el color activado con textbackground.
Sintaxis: cprintf(<formato> , <arg1> , ...);
Prototipo: conio.h

kbhit
Función: Espera la pulsación de una tecla para continuar la ejecución.
Sintaxis: while (!kbhit( )) /* Mientras no pulsemos una tecla... */
Prototipo: conio.h

random
Función: Retorna un valor aleatorio entre 0 y numero_limite-1.
Sintaxis: int <nomb_variable>=random(<numero_limite>);
/* También necesitamos la función randomize */
Prototipo: stdlib.h

(43)
randomize
Función: Inicializa el generador de números aleatorios. Deberemos llamarlo al inicio
de la función en que utilicemos el random. También deberemos utilizar el include
time.h, ya que randomize hace una llamada a la función time, incluida en este último
archivo.

Sintaxis: randomize( );
Prototipo: stdio.h

system
Función: Ejecuta el comando indicado. Esto incluye tanto los comandos del sistema
operativo, como cualquier programa que nosotros le indiquemos. Al acabar la
ejecución del comando, volverá a la línea de código situada a continuación de la
sentencia system.

Sintaxis: system (<comando>); /* p.ej: system("arj a programa"); */


Prototipo: stdlib.h

Conversión de tipos en C++ (CDT)

Entiéndase CDT en C como el cambio de “contexto” de un tipo de dato a otro


“contexto”.
Contexto es la manera en que el computador maneja el dato y opera con él.

En C para realizar por lo general alguna CDT es necesario tener:

Función principal
Funcion(es) auxiliares
Apuntador
Expecificador de formato

A simple vista C++ es bastante particular en la CDT y es un poco más complejo


que Java (porque Java es más “estandarizado”), aunque se adquieren mucha
flexibilidad en la programación. A medida que se le conoce, se puede ir programando
de una manera más elegante en su código fuente.

La conversiones explícitas se fuerzan mediante moldes (casts). La conversión


forzosa de tipos de C tiene el formato clásico:

SINTAXIS: (<TDD>)<expresión>;

C++ ha modificado la notación anterior por una notación funcional como


alternativa sintáctica:

SINTAXIS: <TDD>(<expresión>);

Las notaciones siguientes son equivalentes:

float(x); //notación de casteo en C++


(float)x; //notación de casteo en C

(44)
Ejemplo: Leer un registro y guardar la primera línea tipo carácter en entero.

int main()//acción principal


{
FILE *archivo; //archivo ciudades.txt
int x=0,y=0,a=0,z=0,m=0;
int matriz[10][10]; // declaración de una matriz declarada 10x10
[0..9][0..9]
char arreglo[100]; //arreglo de caracteres de 0 a 99
char n[4]; //arreglo de caracteres
archivo=fopen("ciudades.txt","r"); //Abre el archivo en modo Lectura
printf("\nIntroduzca un numero natural: ");
scanf("%d",&x);//lee la opción de ciudad
if(x==1)
{

//Opción 1
archivo=fopen("ciudades.txt","r");//Abre el archivo en modo Lectura
while(z<y)
{
fgets(arreglo,100,archivo);
/*toma la línea del archivo con 100 caracteres, lo almacena en ARREGLO*/
if(z==(y-1))
{
printf("%s\n\n",arreglo);
/*muestra la información de la ciudad seleccionada*/
}
z++;
}
main(); //recursión para mostrar el menú principal
}
if(x==2)
{
archivo=fopen("ciudades.txt","r"); //Abre el archivo en modo Leer

/*Un archivo se puede abrir varias veces en C*/

fscanf(archivo,"%s",&n); /*Toma la primera linea del archivo y lo


almacena en n*/
printf("\nEl numero de ciudades es: %s\n\n",n); //Muestra el entero
a=atoi(n); /*Transforma el Valor de N a un entero y lo
almacena en "a"*/
printf(“%d”,a); //imprime el entero
}
return 0;
}

(45)
Excepciones en C

Es un mecanismo de gestión de errores incorporado. Permite gestionar y


responder a los errores en tiempo de ejecución. Las excepciones están construidas a
partir de tres palabras clave: try, catch y throw. Cualquier sentencia que provoque
una excepción debe haber sido ejecutada desde un bloque try o desde una función que
este dentro del bloque try.

Cualquier excepción debe ser capturada por una sentencia cath que sigue a la
sentencia try, causante de la excepción.

SINTAXIS:

try

{
<cuerpo>;
}

catch(<tipo_1 arg>)

{
<bloque_1> catch;
}

catch(<tipo_2 arg>)

{
<bloque_2> catch;
}

catch(<tipo_n arg>)

{
<bloque_n> catch;
}

(46)
EJEMPLO:

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
void main()
{
try{
cout<<"Dentro del bloque try\n";
throw 10;
cout<<"Esto se ejecuta si no hay problemas";
}

catch(int i){
cout<<"Capturado el error "<< i;
cout<<"\n";
}

cout << "fin";


getch();
}

Operaciones con Objetos en C++

ASIGNACIÓN DE OBJETOS: Se puede asignar un objeto a otro a condición de


que ambos objetos sean del mismo tipo (misma clase). Cuando un objeto se asigna a
otro se hace una copia a nivel de bits de todos los miembros, es decir se copian los
contenidos de todos los datos. Los objetos continúan siendo independientes.

Sintaxis:

<objeto_destino>=<objeto_origen>;

(47)
EJEMPLO:

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class miclase{
int a,b;
public:
void obtener(int i, int j){a=i;b=j;}
void mostrar(){cout << a << " "<< b << "\n";}
};

void main()
{
miclase o1,o2;
o1.obtener(10,4);
o2=o1;
o1.show();
o2.show();
getch();
}

ARRAY DE OBJETOS: Los objetos son variables y tienen las mismas


capacidades y atributos que cualquier tipo de variables, por tanto es posible disponer
objetos en un array. La sintaxis es exactamente igual a la utilizada para declarar y
acceder al array. También disponemos de arrays bidimensionales.

DECLARACIÓN:

<nombre_clase> <nombre_objeto>[<nº elementos>];


<nombre_clase> <nombre_objeto>[<nº elementos>]=

{<elemento_1>,<elemento_2>,…,<elemento_n>};

INICIALIZACIÓN:

<nombre_objeto>[<índice>].función(<valores>);

(48)
EJEMPLO: Unidimensional.

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class ejemplo{
int a;
public:
void pasar(int x){a=x;}
int mostrar() {return a;}
};
void main()
{
ejemplo ob[4];
int indice;
clrscr();
for(indice=0;indice<4;indice++)
ob[indice].pasar(indice);
for(indice=0;indice<4;indice++)
{
cout << ob[indice].mostrar();
cout << "\n";
}
getch();
}

(49)
EJEMPLO: Bidimensional.

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class bidi{
int a,b;
public:
bidi(int n, int m){a=n;b=m;}
int pasa_a(){return a;}
int pasa_b(){return b;}
};
void main()
{
clrscr();
int fil,col;
bidi objeto[3][2]={
bidi(1,2),bidi(3,4),
bidi(5,6),bidi(7,8),
bidi(9,10),bidi(11,12)};
for(fil=0;fil<3;fil++)
{
for(col=0;col<2;col++)
{
cout << objeto[fil][col].pasa_a();
cout << " ";
cout << objeto[fil][col].pasa_b();
cout << "\n";
}
}
getch();
}

PASO DE OBJETOS A FUNCIONES: Los objetos se pueden pasar a funciones


como argumentos de la misma manera que se pasan otros tipos de datos. Hay que
declarar el parámetro como un tipo de clase y después usar un objeto de esa clase
como argumento cuando se llama a la función. Cuando se pasa un objeto a una
función se hace una copia de ese objeto.

Cuando se crea una copia de un objeto porque se usa como argumento para
una función, no se llama a la función constructora. Sin embargo, cuando la copia se
destruye (al salir de ámbito), se llama a la función destructora.

(50)
PROTOTIPO DE FUNCIÓN:

<TDD_devuelto> <nombre_funcion>(<nombre_clase> <nombre_objeto>)

{
<cuerpo>;
}

LLAMADA A LA FUNCIÓN:

<nombre_funcion>(<objeto>);

EJEMPLO:

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class objetos{
int i;
public:
objetos(int n){i=n;}
int devol(){return i;}
};
int sqr(objetos o)
{
return o.devol()*o.devol();
}
void main()
{
objetos a(10), b(2);
cout << sqr(a);
cout << sqr(b);
getch();
}

OBJETOS DEVUELTOS POR FUCIONES: Al igual que se pueden pasar


objetos, las funciones pueden devolver objetos. Primero hay que declarar la función
para que devuelva un tipo de clase. Segundo hay que devolver un objeto de ese tipo
usando la sentencia return.

Cuando un objeto es devuelto por una función, se crea automáticamente un


objeto temporal que guarda el valor devuelto. Este es el objeto que realmente
devuelve la función. Después el objeto se destruye, esto puede causar efectos laterales
inesperados.

(51)
EJEMPLO:

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
class ejemplo{
char cadena[80];
public:
void muestra(){cout<<cadena<<"\n";}
void copia(char *cad){strcpy(cadena,cad);}
};
ejemplo entrada()
{
char cadena[80];
ejemplo str;
cout<<"Introducir cadena: ";
cin>>cadena;
str.copia(cadena);
return str;
}
void main()
{
ejemplo ob;
ob=entrada();
ob.muestra();
getch();
}

PUNTEROS A OBJETOS: Hasta ahora se ha accedido a miembros de un objeto


usando el operador punto. Es posible acceder a un miembro de un objeto a través de
un puntero a ese objeto. Cuando sea este el caso, se emplea el operador de flecha
(->) en vez del operador punto. Para obtener la dirección de un objeto, se precede al
objeto con el operador &. Se trabaja de igual forma que los punteros a otros tipos.

(52)
EJEMPLO:

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class miclase{
int a;
public:
miclase(int x);
int get();
};
miclase::miclase(int x)
{
a=x;
}
int miclase::get()
{
return a;
}
void main()
{
clrscr();
miclase obj(200);
miclase *p;
p=&obj;
cout << "El valor del Objeto es " << obj.get();
cout << "El valor del Puntero es " << p->get();
getch();
}

Funciones Constructoras y Destructoras

En los programas hay partes que requieren inicialización. Esta necesidad de


inicialización es incluso más común cuando se está trabajando con objetos. Para tratar
esta situación, C++ permite incluir una función constructora. A estas funciones se las
llama automáticamente cada vez que se crea un objeto de esa clase.

La función constructora debe tener el mismo nombre que la clase de la que es


parte, no tienen tipo devuelto, es ilegal que un constructor tenga un tipo devuelto.
Pero si es posible pasarle valores a modo de parámetros.

Prototipo de la función:
<nombre_función>(<parámetros>);

Desarrollo de la función:
<nombre_clase>::<nombre_función>(<parámetros>){cuerpo;}

(53)
EJEMPLO:

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class miclase{
int a;
public:
miclase();
void show();
};

miclase::miclase()
{
a=100;
}

void miclase::show()
{
cout << a;
}

void main()
{
clrscr();
miclase obj;
obj.show();
getch();
}

El complemento de un constructor es la función destructora. A esta función se la


llama automáticamente cuando se destruye el objeto. El nombre de las funciones
destructoras debe ser el mismo que el de la clase a la que pertenece precedido del
carácter ~ (alt+126). Los objetos de destruyen cuando se salen de ámbito cuando son
locales y al salir del programa si son globales. Las funciones destructoras no devuelven
tipo y tampoco pueden recibir parámetros.

Técnicamente un constructor y un destructor se utilizan para inicializar y


destruir los objetos, pero también se pueden utilizar para realizar cualquier otra
operación. Sin embargo esto se considera un estilo de programación pobre.

PROTOTIPO DE LA FUNCIÓN DESTRUCTOR:

~<nombre_función>(<parámetros>);

(54)
DESARROLLO DE LA FUNCION:

<nombre_clase>::<nombre_función>()

{
<cuerpo>;
}

EJEMPLO: Mismo programa de antes añadiendo una función destructora.

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class miclase{
int a;
public:
miclase();
~miclase();
void show();
};

miclase::miclase()
{
a=100;
}

miclase::~miclase()
{
cout << "Destruyendo...\n";
getch();
}

void miclase::show()
{
cout << a;
}

void main()
{
clrscr();
miclase obj;
obj.show();
getch();
}

(55)
CONSTRUCTORES CON PARAMETROS: Es posible pasar argumentos a una función
constructora. Para permitir esto, simplemente añada los parámetros a la declaración y
definición de la función constructora. Después, cuando declare un objeto, especifique
los parámetros como argumentos.

EJEMPLO:

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class miclase{
int a;
public:
miclase(int x);
void mostrar();
};

miclase::miclase(int x)
{
cout << "Constructor";
a=x;
}

void miclase::miclase()
{
cout <<"El valor de a es: ";
cout << a;
}

void main()
{
miclase objeto(4);
ob.show();
getch();
}

Sobrecarga de Funciones y Operadores

En C++ dos o más funciones pueden compartir el mismo nombre en tanto en cuanto difiera
el tipo de sus argumentos o el número de sus argumentos o ambos. Cuando comparten el
mismo nombre y realizan operaciones distintas se dice que están sobrecargadas. Para
conseguir la sobrecarga simplemente hay que declarar y definir todas las versiones
requeridas.

También es posible y es muy común sobrecargar las funciones constructoras. Hay 3 razones
por las que sobrecargar las funciones constructoras. Primero ganar flexibilidad, permitir
arrays y construir copias de constructores

(56)
EJEMPLO:

#include <iostream.h>
#include <conio.h>
#include <stdio.h>
int abs(int numero);
long abs(long numero);
double abs(double numero);

void main()
{
clrscr();
cout <<"Valor absoluto de -10 "<< abs(-10) <<"\n";
cout <<"Valor absoluto de -10L "<< abs(-10L) <<"\n";
cout <<"Valor absoluto de -10.01 "<< abs(-10.01) <<"\n";
getch();
}

int abs(int numero)


{
return numero<0 ? -numero:numero;
}
long abs(long numero)
{
return numero<0 ? -numero:numero;
}
double abs(double numero)
{
return numero<0 ? -numero:numero;
}

/*EJEMPLO otro programa*/


#include <iostream.h>
#include <stdio.h>
#include <conio.h>
void fecha(char *fecha);
void fecha(int anno, int mes, int dia);
void main()
{
clrscr();
fecha("23/8/98");
fecha(98,8,23);
getch();
}
void fecha(char *fecha)
{
cout<<"Fecha: "<<fecha<<"\n";
}
void fecha(int anno,int mes,int dia)
{
cout<<"Fecha: "<<dia<<"/"<<mes<<"/"<<anno;
}

(57)
ARGUMENTOS IMPLICITOS: Otra característica relacionada con la sobrecarga
es la utilización de argumentos implícitos que permite dar un valor a un parámetro
cuando no se especifica el argumento correspondiente en la llamada a la función.

PROTOTIPO:

<TDD_devuelto>(<var_1>=<valor>,<var_2>=<valor>,<var_n>=<valor>);

EJEMPLO:

#include<iostream.h>
#include<stdio.h>
#include<conio.h>
void funcion(int a=0, int b=0)
{
cout<<"a: "<< a <<" b: "<< b <<"\n";
}

void main()
{
clrscr();
funcion();
funcion(10);
funcion(20,30);
getch();
}

Es muy similar a la sobrecarga de funciones, un operador siempre se


sobrecarga con relación a una clase. Cuando se sobrecarga un operador no pierde su
contenido original, gana un contenido relacionado con la clase. Para sobrecargar un
operador se crea una función operadora que normalmente será una función amiga a la
clase.

PROTOTIPO:

<TDD_devuelto> <nombre_clase>::<operador> <operador>(<parámetros>)


{
<cuerpo>;
}

(58)
Se pueden realizar cualquier actividad al sobrecargar los operadores pero es mejor que
las acciones de un operador sobrecargado se ajusten al uso normal de ese operador.
La sobrecarga tiene dos restricciones, no puede cambiar la precedencia del operador y
que el numero de operadores no puede modificarse. También hay operadores que no
pueden sobrecargarse.

OPERADORES
.
::
¿??
.*

Existen 3 tipos de sobrecarga de operadores. Operadores binarios, operadores


lógicos-relacionales y operadores unarios. Cada uno de ellos debe tratarse de una
manera específica para cada uno de ellos.

BINARIOS: La función solo tendrá un parámetro. Este parámetro contendrá al


objeto que este en el lado derecho del operador. El objeto del lado izquierdo es el que
genera la llamada a la función operadora y se pasa implícitamente a través de this.

(59)
EJEMPLO:

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class opera{
int x, y;
public:
opera() {x=0;y=0;}
opera(int i, int j) {x=i; y=j;}
void obtenxy(int &i,int &j) {i=x; j=y;}
opera operator+(opera obj);
};

opera opera::operator+(opera obj)


{
opera temp;
temp.x=x+obj.x;
temp.y=y+obj.y;
return temp;
}

void main()
{
opera obj1(10,10), obj2(5,3),obj3;
int x,y;
obj3=obj1+obj2;
obj3.obtenxy(x,y);
cout << "Suma de obj1 mas obj2\n ";
cout << "Valor de x: "<< x << " Valor de y: " << y;
getch();
}

LÓGICOS Y RELACIONALES: Cuando se sobrecargan dichos operadores no se


deseará que las funciones operadoras devuelvan un objeto, en lugar de ello,
devolverán un entero que indique verdadero o falso. Esto permite que los operadores
se integren en expresiones lógicas y relacionales más extensas que admitan otros tipos
de datos.

(60)
EJEMPLO:

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class opera{
int x,y;
public:
opera() {x=0;y=0;}
opera(int i,int j) {x=i; y=j;}
void obtenerxy(int &i, int &j) {i=x; j=y;}
int operator==(opera obj);
};

int opera::operator==(opera obj)


{
if(x==obj.x && y==obj.y)
return 1;
else
return 0;
}

void main()
{
clrscr();
opera obj1(10,10), obj2(5,3);
if(obj1==obj2)
cout << "Objeto 1 y Objeto 2 son iguales";
else
cout << " Objeto 1 y objeto 2 son diferentes";
getch();
}

UNARIOS: El miembro no tiene parámetro. Es el operando el que genera la


llamada a la función operadora. Los operadores unarios pueden preceder o seguir a su
operando, con lo que hay que tener en cuenta como se realiza la llamada.

(61)
EJEMPLO:

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class opera{
int x, y;
public:
opera() {x=0;y=0;}
opera(int i, int j) {x=i;y=j;}
void obtenxy(int &i, int &j) {i=x; j=y;}
opera operator++();
};

opera opera::operator++()
{
x++;
y++;
}

void main()
{
clrscr();
opera objeto(10,7);
int x,y;
objeto++;
objeto.obtenxy(x,y);
cout<< "Valor de x: " << x <<" Valor de y: "<< y << "\n";
getch();
}

Prioridad de operadores:

() (Paréntesis) +

-(unario),/\,\/ (negación, y , o )

div,mod,*,/ (división en N, multiplicación y división)

+,- (suma, resta)

>=,<=,<,> (Relaciones de orden)

=,≠ (Relación)

o,y (operadores lógicos)

--> (Asignación) _

(62)
Funciones InLine y Automáticas

La ventaja de las funciones insertadas es que se pueden ejecutar más


rápidamente que las funciones normales. La llamada y vuelta de una función normal
tardan tiempo y si tienen parámetros incluso más. Para declarar este tipo de funciones
simplemente hay que preceder la definición de la función con el especificador inline.

Sintaxis:

inline <TDD_devuelto> <nombre_función> ( <parámetros> ){<cuerpo>;}

Las llamadas a las funciones insertadas se realizan de la misma manera que


cualquier función. Uno de los requisitos es que se tiene que definir antes de llamarla,
es decir definir y desarrollar antes de la función main.

Si el compilador no es capaz de cumplir la petición, la función se compila como


una función normal y la solicitud inline se ignora. Las restricciones son cuatro, no
puede contener variables de tipo static, una sentencia de bucle, un switch o un goto.

EJEMPLO: En este programa utilizamos una función inline pasando valores. No


usa clases ni objetos.

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
inline int valor(int x) { return ¡!(X%2);}
void main()
{
int a;
cout <<"Introducir valor: ";
cin >> a;
if (valor(a))
cout << "Es par ";
else
cout << "Es impar";
}

La característica principal de las funciones automáticas es que su definición es


lo suficientemente corta y puede incluirse dentro de la declaración de la clase. La
palabra inline no es necesaria. Las restricciones que se aplican a las funciones inline se
aplican también para este tipo. El uso más común de las funciones automáticas es para
funciones constructoras.

Sintaxis

<valor_devuelto><nombre_función> (<parámetros>){<cuerpo>;}

(63)
EJEMPLO: Mismo programa anterior pero sin utilizar inline.

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class ejemplo{
public:
int valor(int x) { return ¡!(X%2);}
};

void main()
{
int a;
cout <<"Introducir valor: ";
cin >> a;
if (valor(a))
cout << "Es par ";
else
cout << "Es impar";
}

Utilización de Estructuras como Clases

En C++, la definición de una estructura se ha ampliado para que pueda también


incluir funciones miembro, incluyendo funciones constructoras y destructoras como
una clase. De hecho, la única diferencia entre una estructura y una clase es que, por
omisión, los miembros de una clase son privados y los miembros de una estructura son
públicos.

struct <nombre>{
/*variables y funciones publicas; */
private: /*es un MDA*/
/*variables y funciones privadas;*/
};

Aunque las estructuras tienen las mismas capacidades que las clases, se
reserva el uso de struct para objetos que no tienen funciones miembro. Una de las
razones de la existencia de las estructuras es mantener compatibilidad con los
programas hechos C.

(64)
EJEMPLO:

#include <iostream.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>
struct tipo{
tipo(double b, char *n);
void mostrar();
private:
double balance;
char nombre[40];
};

tipo::tipo(double b, char *n)


{
balance=b;
strcpy(nombre,n);
}

void tipo::mostrar()
{
cout << "Nombre: " << nombre;
cout << ": $" << balance;
if (balance<0.0) cout << "****";
cout << "\n";
}

void main()
{
clrscr();
tipo acc1(100.12,"Ricardo");
tipo acc2(-12.34,"Antonio");
acc1.mostrar();
getch();
clrscr();
acc2.mostrar();
getch();
}

Como ejemplo a lo anterior crearemos el primer programa utilizando objetos y


clases para ver la teoría llevada a la práctica. Seguiremos utilizando las mismas
sentencias que usábamos en C, más adelante los programas tomarán la estructura
exclusiva de C++.

(65)
EJEMPLO:

#include <stdio.h>
#include <conio.h>

class miclase{
int a;
public:
void pasar_a(int num);
int mostrar_a();
};

void miclase::pasar_a(int num)


{
a=num;
}

int miclase::mostrar_a()
{
return a;
}

void main()
{
miclase obj1, obj2;
clrscr();
obj1.pasar_a(10);
obj2.pasar_a(99);
printf("%d\n",obj1.mostrar_a());
printf("%d\n",obj2.mostrar_a());
getch();
}

This, New y Delete

This es un puntero que se pasa automáticamente a cualquier miembro cuando


se invoca. Es un puntero al objeto que genera la llamada, por tanto la función recibe
automáticamente un puntero al objeto. A este puntero se referencia como this y solo
se pasa a los miembros punteros this.

Sintaxis:

<objeto.funcion>(); // a la función recibe automáticamente el puntero this.

(66)
EJEMPLO: El primero sin puntero this. El segundo utilizando el puntero this.

// 1.-
#include <iostream.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
class stock{
char item[20];
double coste;
public:
stock(char *i,double c)
{
strcpy(item,i);
coste=c;
}
void muestra();
};

void stock::muestra()
{
cout<<item << "\n";
cout<<"PVP: " << coste;
}

void main()
{
clrscr();
stock obj("tuerca",5.94);
obj.muestra();
getch();
}

// 2.-
#include <iostream.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
class stock{
char item[20];
double coste;
public:
stock(char *i,double c)
{
strcpy(this->item,i);
this->coste=c;
}
void muestra();
};

(67)
void stock::muestra() /*Esta es la continuación el código*/
{
cout<<this->item << "\n";
cout<<"PVP: " << this->coste;
}

void main()
{
clrscr();
stock obj("tuerca",5.94);
obj.muestra();
getch();
}

Hasta ahora si se necesitaba asignar memoria dinámica, se hacía con malloc y


para liberar se utilizaba free. En C++ se puede asignar memoria utilizando new y
liberarse mediante delete. Estos operadores no se pueden combinar unas con otras,
es decir debe llamarse a delete solo con un puntero obtenido mediante new. Los
objetos también se les puede pasar un valor inicial con la sentencia new.

SINTAXIS:

<nombre_puntero> =new <tipo>;


delete <nombre_puntero>;
<nombre_puntero>=new <TDD>(<valor_inicial>);

También se pueden crear arrays asignados dinámicamente, estos arrays pueden


utilizar la sentencia new. La sintaxis general es:

DECLARACION DEL ARRAY:

SINTAXIS:

<nombre_puntero>=new <TDD>[<tamaño>]; /*sin inicializar*/

EJEMPLO:

#include<iostream.h>
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
class cosas{
int i,j;
public:
void obten(int a,int b){i=a;j=b;}
int muestra(){return i*j;}
};

(68)
Ejemplo:

void main()
{
clrscr();
int *p_var;
p_var=new int;
//p_var=new int(9); se asigna un valor inicial.
cosas *p;
p=new cosas;
if(!p || !p_var)
{
cout<<"Error de asignacion\n";
exit(1);
}

*p_var=1000;
p->obten(4,5);
cout<<"El entero en p_var es: " <<*p_var;
cout<<"\nTotal: " <<p->muestra();
getch();
}

EJEMPLO: Array asignado dinámicamente.

#include<iostream.h>
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
void main(void)
{
int *p;
int i;
p=new int[5];
clrscr();
if(!p)
{
cout<<"Error de asignacion\n";
exit(1);
}
for(i=0;i<5;i++)
p[i]=i+1;
for(i=0;i<5;i++)
{
cout<<"Este es el entero en p["<<i<<"]:";
cout<<p[i]<<"\n";
}
delete[] p;
getch();
}

(69)
Referencias

C++ consta de una particularidad relacionada con los punteros, denominada


referencia. Una referencia es un puntero implícito que se comporta como una
variable normal siendo un puntero. Existen tres modos de utilizar una referencia. Se
puede pasar a una función, ser devuelta de una función y crearse como una referencia
independiente. Lo que apunta una referencia no puede ser modificado. El caso de las
referencias independientes es muy poco común y casi nunca se utilizan, en este
manual no se hace referencia a ellas.

En el ejemplo siguiente se compara un programa que utiliza un puntero normal


y otro programa que realiza las mismas operaciones utilizando una referencia que se
pasa a una función.

EJEMPLO:

//Utilizando punteros normal.


#include <iostream.h>
#include <stdio.h>
#include <conio.h>
void f(int *n);
void main()
{
int i=0;
f(&i);
cout<<"valor i:" << i;
getch();
}
void f(int *n)
{
*n=100;
}

//Utilizando referencias.
#include <iostream.h>
#include <stdio.h>
#include <conio.h>
void f(int &n);
void main()
{
int i=0;
f(i);
cout<<"valor i:"<< i;
getch();
}

void f(int &n)


{
n=100;
}

(70)
En el caso de las referencias devueltas por una función se puede poner el
nombre de la función en el lado izquierdo de la expresión. Es como asignar un valor a
una variable. Hay que tener en cuenta el ámbito de la variable que se comporta como
una referencia.

EJEMPLO:

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
int &f();
int x;
void main()
{
clrscr();
f()=100;
cout<<"Valor de x: " <<x;
getch();
}

int &f()
{
return x;
}

Herencia

Para empezar, es necesario definir dos términos normalmente usados al tratar


la herencia. Cuando una clase hereda otra, la clase que se hereda se llama clase base.
La clase que hereda se llama clase derivada. La clase base define todas las cualidades
que serán comunes a cualquier clase derivada. Otro punto importante es el acceso a la
clase base. El acceso a la clase base pude tomar 3 valores, public, private y
protected.

Si el acceso es public, todos los atributos de la clase base son públicos para la
derivada.

Si el acceso es private, los datos son privados para la clase base la derivada no
tiene acceso.

Si el acceso es protected, datos privados para la base y derivada tiene acceso,


el resto sin acceso.

La clase derivada se le conoce tambien como “clase hija” y a la clase base se le


conoce tambien como “clase madre”.

(71)
EJEMPLO: para comprobar los distintos tipos de acceso.

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class miclase{
int a;
protected:
int b;
public:
int c;
miclase(int n,int m){a=n;b=m;}
int obten_a(){return a;}
int obten_b(){return b;}
};

void main()
{
miclase objeto(10,20);
clrscr();
objeto.c=30;
// objeto.b=30; error,sin acceso.
// objeto.a=30; error,sin acceso.
cout<<objeto.obten_a() <<"\n";
cout<<objeto.obten_b() <<"\n";
cout<<objeto.c;
getch();
}

FORMATO DE “la clase hija” (sintaxis):

class <nombre_de_clase_hija>:<MDA> <nombre_de_clase_madre>{


<cuerpo>;
};
Herencia Simple
EJEMPLO: Herencia pública.
#include <iostream.h> Clase Madre:
#include <stdio.h>
#include <conio.h>
class base{
“Conjunto de
int x; objetos”
public:
void obten_x(int a){x=a;}
void muestra_x(){cout<< x;}
}; Clase Hija:
class derivada:public base{
int y; “Prototipos de objetos heredados”
public: (Encapsulamiento)
void obten_y(int b){y=b;}
void muestra_y(){cout<<y;}
};

(72)
void main() /*este código es la continuación de otro*/
{
derivada obj; /*obj es una variable de tipo derivada*/
clrscr(); /*se limpia la pantalla*/
obj.obten_x(10); /*se llama al método “obten_x” heredado en derivada*/
obj.obten_y(20); /*se llama al método “obten_y” propio de derivada*/
obj.muestra_x();/*se llama al método “muestra_x” heredado en derivada*/
cout<<"\n"; /*imprime una salida*/
obj.muestra_y(); /*se llama al método “muestra_y” propio de derivada*/
getch(); /*se lee un carácter*/
}

EJEMPLO: Herencia con acceso privado.


#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class base{
int x;
public:
void obten_x(int a){x=a;}
void muestra_x(){cout<<x <<"\n";}
};

class derivada:private base{


int y;
public:
void obten_xy(int a,int b){obten_x(a);y=b;}
void muestra_xy(){muestra_x();cout<<y<<"\n";}
};

void main()
{
clrscr();
derivada ob;
ob.obten_xy(10,20);
ob.muestra_xy();
// ob.obten_x(10); error,sin acceso.
// ob.muestra_x(); error,sin acceso.
getch();
}

HERENCIA MULTIPLE: Existen dos métodos en los que una clase derivada
puede heredar más de una clase base. El primero, en el que una clase derivada puede
ser usada como la clase base de otra clase derivada, creándose una jerarquía de
clases. El segundo, es que una clase derivada puede heredar directamente más de
una clase base. En esta situación se combinan dos o más clases base para facilitar la
creación de la clase derivada.

(73)
SINTAXIS: Para construir la derivada mediante varias clases base.

class <nom_derivada>:<MDA> <nomb_base1>,<nomb_base2>,<nomb_baseN<{


<cuerpo>; /*<nomb_base_n> = <nombre_clase_base_n>*/
};

SINTAXIS: Para crear herencia múltiple de modo jerárquico.

class <nomb_derivada_1>:<MDA> <nomb_clase_base_1> {


<cuerpo>;
};

class <nomb_derivada_2>:<MDA> < nomb_derivada_1> {


<cuerpo>;
};

class <nomb_derivada_N>:<MDA> < nomb_derivada_(N-1)>{


<cuerpo>;
};

EJEMPLO: Herencia de tipo jerárquica.

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class base_a{
int a;
public:
base_a(int x){a=x;}
int ver_a(){return a;}
};

class deriva_b:public base_a

{
int b;
public:
deriva_b(int x, int y):base_a(x){b=y;}
int ver_b(){return b;}
};

(74)
class deriva_c:public deriva_b

{
int c;
public:
deriva_c(int x,int y,int z):deriva_b(x,y){c=z;}
void ver_todo()
{
cout<<ver_a()<<" "<<ver_b()<<" "<<c;
}
};

void main()
{
clrscr();
deriva_c ob(1,2,3);
ob.ver_todo();
cout<<"\n";
cout<<ob.ver_a()<<" "<<ob.ver_b();
getch();
}

El caso de los constructores es un poco especial. Se ejecutan en orden


descendente, es decir primero se realiza el constructor de la clase base y luego el de
las derivadas. En las destructoras ocurre en orden inverso, primero el de las derivadas
y luego el de la base.

EJEMPLO: Múltiple heredando varias clases base.

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class B1{
int a;
public:
B1(int x){a=x;}
int obten_a(){return a;}
};

class B2{
int b;
public:
B2(int x){b=x;}
int obten_b(){return b;}
};

class C1:public B1,public B2{


int c;

(75)
public:
C1(int x,int y,int z):B1(z),B2(y)
{
c=x;
}
void muestra()
{
cout<<obten_a()<<" "<<obten_b()<<" ";
cout<<c<<"\n";
}
};

void main()
{
clrscr();
C1 objeto(1,2,3);
objeto.muestra();
getch();
}

Funciones Virtuales

Una función virtual es miembro de una clase que se declara dentro de una clase
base y se redefine en una clase derivada. Para crear una función virtual hay que
preceder a la declaración de la función la palabra clave virtual. Debe tener el mismo
tipo y numero de parametros y devolver el mismo tipo.

Cada redefinición de la función virtual en una clase derivada expresa el


funcionamiento especifico de la misma con respecto a esa clase derivada. Cuando se
redefine una función virtual en una clase derivada NO es necesaria la palabra virtual.

EJEMPLO:

#include<iostream.h>
#include<stdio.h>
#include<conio.h>
class base{
public:
int i;
base(int x){i=x;}
virtual void func(){cout<<i<<"\n";}
};

class derivada1:public base{


public:
derivada1(int x):base(x){};
void func(){ cout <<i*i<<"\n";}
};

(76)
class derivada2:public base{
public:
derivada2(int x):base(x){};
void func(){cout<<i+i;}
};

void main()
{
base obj1(10);
derivada1 obj2(10);
derivada2 obj3(10);
obj1.func();
obj2.func();
obj3.func();
getch();
}

Funciones Amigas

Habrá momentos en los que se quiera que una función tenga acceso a los
miembros privados de una clase sin que esa función sea realmente un miembro de esa
clase. De cara a esto están las funciones amigas. Son útiles para la sobrecarga de
operadores y la creación de ciertos tipos de funciones E/S.

El prototipo de esta funciones viene precedido por la palabra clave friend,


cuando se desarrolla la función no es necesario incluir friend. Una función amiga no es
miembro y no se puede calificar mediante un nombre de objeto. Estas funciones no se
heredan y pueden ser amigas de más de una clase.

PROTOTIPO: (sintaxis)

friend <TDD_devuelto> <nombre_función> (<parámetros>);

DESARROLLO:

<TDD_devuelto> < nombre_función> (<parámetros>)

{
<cuerpo>;
}

(77)
EJEMPLO:

#include <iostream.h>
#include <stdio.h>
#include <conio.h>
class miclase{
int n,d;
public:
miclase(int i, int j){n=i;d=j;}
friend int factor(miclase ob);
};

int factor(miclase ob)


{
if (!(ob.n%ob.d))
return 1;
else
return 0;
}

void main()
{
miclase obj1(10,2), obj2(3,2);
if(factor(obj1))
cout << "es factor";
else
cout << "no es factor";
getch();
}

(78)
Tipo de Dato Referencia

Tambien llamado apuntador, o pointer. Una referencia no es más que un tipo de


dato elemental que representa una dirección de memoria en donde por lo general se
encuentra un dato, sea elemental o estructurado.

Los apuntadores son la base para la creación de la mayoría de las estructuras


dinámicas, como listas, árboles y grafos. La cantidad de memoria que ocupa cada
variable tipo referencia es una palabra.

Apuntadores en C (tambien se les conoce como “punteros”)

Un Apuntador es una variable que contiene una dirección de memoria, la cual


corresponderá a un dato o a una variable que contiene el dato. Los apuntadores
también deben de seguir las mismas reglas que se aplican a las demás variables,
deben tener nombre únicos y deben de declararse antes de usarse.

Cada variable que se utiliza en una aplicación ocupa una o varias posiciones de
memoria. Estas posiciones de memoria se acceden por medio de una dirección:

En la figura el texto Hello ésta guardado en memoria, comenzando en la


dirección 1000. Cada carácter ocupa un espacio de dirección único en memoria. Los
apuntadores proporcionan un método para conservar y llegar a estas direcciones en
memoria. Los apuntadores facilitan el manejo de datos, debido a que conservan la
dirección de otra variable o ubicación de datos.

Por qué son Importantes los Apuntadores?

Los apuntadores dan flexibilidad a los programas en C++ y permiten que estos
crezcan dinámicamente. Utilizando un apuntador hacia un bloque de memoria que se
asigna al momento de ejecución, un programa puede ser más flexible que uno que
asigna toda su memoria de una sola vez. También, un apuntador es más fácil de
guardar que una estructura grande o un objeto de una clase. Debido a que un
apuntador sólo guarda una dirección, puede fácilmente pasarse a una función. Uno de
las desventajas que pueden presentar los apuntadores es que un apuntador sin control
o no inicializado puede provocar fallas en el sistema, además de que su uso incorrecto
puede generar fallas muy complejas de hallar.

Operadores de Indirección y Dirección:

Hay 2 operadores que se usan cuando trabajan con direcciones en un programa


C; el Operador de Indirección ( * ) y el de Dirección ( & ). Estos operadores son
diferentes de los tratados anteriormente.

(79)
El Operador de Dirección ( & ) regresa la dirección de una variable. Este
operador está asociado con la variable a su derecha: &h; Esta línea regresa la dirección
de la variable h.

El Operador de Indirección ( * ) trabaja a la inversa del operador de Dirección.


También esta asociado con la variable a su derecha, toma la dirección y regresa el
dato que contiene esa dirección. Por ejemplo, la siguiente línea determina la dirección
de la variable h y luego usa el operador de Indirección para acceder a la variable y
darle un valor de 42:

*(&h)=42;

int n; // es un tipo de dato entero

int *p; // p es un puntero a un entero


/*Una vez declarado un puntero, se puede fijar la dirección o posición de memoria del
tipo al que apunta.*/
p = &n; //p se fija a la dirección de a

Una vez que se ha declarado un puntero, p el objeto al que apunta se escribe


*p y se puede tratar como cualquier otra variable de tipo <NombreTipo>.

int *p, *q, o; // dos punteros a integer, y una variable integer


*P = 101; // *p apunta 101
*q= n + *p; // *q apunta a n mas el contenido de lo que apunta p

C++ trata los punteros a tipos diferentes como TDD diferentes,

int *ip;
double *dp;

Los punteros ip y dp son incompatibles, de modo que es un error escribir:


dp = ip;

Se pueden, sin embargo, realizar asignaciones entre contenidos, ya que se


realizaría una conversión explícita de tipos: *dp =ip.

Existe un puntero especial (nulo) que se suele utilizar con frecuencia en


programas C++. El puntero NULL tiene un valor cero, que lo diferencia de todas las
direcciones válidas. El conocimiento nos permite comprobar si un puntero p es el
puntero NULL evaluando la expresión (p==0). Los punteros NULL se utilizan sólo como
señales de que ha sucedido algo. En otras palabras, si p es un puntero NULL, es
incorrecto referenciar *p.

(80)
SINTAXIS La declaración de un puntero de manera general es:

<tipo> *<nombre_de_apuntador>(<variable>);

<tipo>: Especifica el tipo de objeto apuntado y puede ser cualquier tipo.

<nombre de apuntador>: Es el identificador del apuntador.

El espacio de memoria requerido para un apuntador, es el número de bytes


necesarios para especificar una dirección de memoria, debiendo apuntar siempre al
tipo de dato correcto.

Advertencia sobre C: En el lenguaje C como cualquier otro lenguaje que


manipula objetos cada uno de ellos debe tener como mínimo un apuntador asignado, si
un objeto queda sin un apuntador para él, queda “aislado” en algún lugar de la
memoria ocupando un espacio, motivo por el cual algunos lenguajes emplean un
Recolector de Basura de modo que cada cierto tiempo elimina los objeto que quedan
aislados (sin apuntador) generalmente por descuido del programador, excepto C,
donde se tiene libre acceso a todas las direcciones memoria. Por esto en Java se
restringe el acceso a la memoria del computador por motivos de seguridad, pero se
puede acceder a su valor y se verifica siempre el espacio de memoria asignado al
programa que se construye a fin de que por algún descuido del programador, el
programa no termine modificando espacios en memoria asignados a otros datos
reservados relacionados con códigos de otros programas. Por esta razón, Java es más
lento que C en la compilación. Si un programa en lenguaje C sobrescribe su espacio de
memoria asignado a él, podría causar daños en otros programas al alterar sus códigos
fuentes que están almacenados, e incluso asta del S.O. Si un apuntador en C apunta a
una dirección donde se encuentra un dato del sistema operativo y lo modifica esto
pondría causar daños graves al S.O. aunque algunos se beneficien de ello.

Considere el siguiente programa y observe a las variables de dirección e


Indirección trabajar:

(81)
La Aritmética de Apuntadores.

Generalidades:

Las operaciones más comunes son la asignación y las relacionales. Por lo


general sólo interesa comparaciones de = y !=; raramente necesitaremos comparar
una dirección con otra con los operadores > y <. Algunos lenguajes soportan
aritmética de punteros, en donde podemos incrementar o decrementar una dirección
de memoria. En el caso de la asignación, es importante que ambas asignaciones
apunten a elementos del mismo tipo, pues de lo contrario se podrían acceder e
interpretar datos de manera errónea. Dos apuntadores son iguales si almacenan la
misma dirección de memoria.

En C solamente se pueden realizar operaciones de incremento y decremento, y


estos es de acuerdo a la longitud de su tipo de base. Por ejemplo supóngase que una
máquina particular utiliza direccionamiento de byte, un entero requiere 4 bytes y el
valor de la variable pi (declarada así: int *pi) es 100, es decir, se apunta al entero *pi
en la localidad 100. Entonces el valor de pi-1 es 96, el de pi+1 es 104 y el de pi+2 es
108. El valor de *(pi-1) es el de los contenidos de los 4 bytes 96,97,98, y 99 , el de
*(pi+1) es el del contenido de los byte 104, 105,106 y 107, y el de *(pi+2) es el
entero que esta en los bytes 108,109,110 y 111.

De manera parecida, si el valor de la variable pc (declarada así: char *pc; ) es


igual a 100, y un carácter tiene un byte de longitud, pc-1 refiere a la localidad 99,
pc+1 a la 101 y pc+2 a la 102.

Dado que los punteros son números (direcciones), pueden ser manipulados por
los operadores aritméticos. Las operaciones que están permitidas sobre punteros son:
suma, resta y comparación.

Así, si las sentencias siguientes se ejecutan en secuencia:

char *p; // p, contiene la dirección de un carácter


char a[l0]; // array de diez caracteres
p = &a[0]; // p, apunta al primer elemento del array
p++; // p, apunta al segundo elemento del array
p++; // p, apunta al tercer elemento del array
p--; // p, apunta al segundo elemento del array

(82)
Un elemento de comparación de punteros, es el siguiente programa:

#include <iostream.h>
main (void)
{
int *ptr1, *ptr2;
int a[2] = {l0,l0};
ptrl = a;
cout << “ptr1 es ” << ptr1 << ” *ptr1 es “ << *ptr1 << endl;
cout << “ptr2 es ” << ptr2 << ” *ptr2 es “ << *ptr2 << endl;
//comparar dos punteros
if (*ptrl == *ptr2)
cout << ”ptr1 es igual a *ptr2 \n”;
else
cout << “*ptrl no es igual a *ptr2 \n”;
}

Apuntadores a Funciones

Un área en la cual desempeñan un papel prominente los apuntadores es el


lenguaje C es la transmisión de parámetros a funciones. Por lo común, los parámetros
se transmiten por valor a una función en C, es decir, se copian los valores transmitidos
en los parámetros de la función llamada en el momento en que se invoca. Si cambia el
valor de un parámetro dentro de la función, no cambia su valor en el programa que la
llama. Por ejemplo considérese el siguiente fragmento y función de programa (el
número de línea es solo una guía en el ejemplo):

(83)
La línea 2 imprime el número 5 y después llama a funct. El valor de "x", que es
5, se copia en "y" y comienza la ejecución de funct. Después, la línea 9 imprime el
número 6 y regresa funct. Sin embargo, cuando la línea 8 incrementa el valor de "y",
el valor de "x" permanece invariable. Así, la línea 4 imprime el número 5, "x" y "y"
refieren a 2 variables diferentes.

Si deseamos usar funct para modificar el valor de "x", debemos de transmitir


la dirección de "x" de la siguiente manera:

La línea 2 imprime nuevamente el número 5, y la línea 3 llama a funct. Ahora,


sin embargo, el valor transferido no es el valor entero de "x" sino el valor apuntador
"&x". Este es la dirección de "x". El parámetro de funct no es más y de tipo int, sino py
de tipo int * . (Es conveniente nombrar a las variables apuntadores comenzando con la
letra p para recordar tanto que se trata de un apuntador) la línea 8 ahora aumenta al
entero en la localidad py; py, sin embargo, no cambia y conserva su valor inicial "&x".
Así, py apunta al entero "x" de tal manera que cuando *py, aumenta x. La línea 9
imprime 6 y cuando regresa funct, la línea 4 imprime también 6. Los apuntadores son
el mecanismo usado en el lenguaje C para permitir a una función llamada modificar las
variables de la función que llama.

Arreglos en C

Arreglos. Es una serie de datos del mismo tipo, también conocidos como
vectores o rangos. Una arreglo esta constituido por varias posiciones de memoria de
igual tamaño consecutivas que tienen el mismo tipo de variable y se accesan usando el
mismo nombre seguido de un subíndice entre corchetes. La cantidad total de espacio
que se usa por un arreglo depende de 2 cosas: El número de elementos en el arreglo y
El tamaño del arreglo.

(84)
¿Por qué Usar los Arreglos?

Por que son uno de los factores esenciales de los programas de computadora.
Permiten que se haga referencia a entradas individuales en una tabla de elementos de
datos usando el mismo código y variando el índice del elemento.

La Declaración de un Arreglo: es igual a como se haría con una variable, a


excepción de que también se especifica la cantidad de elementos en el arreglo
encerrado entre corchetes de la siguiente manera:

<tipo> <nombre_del_arreglo>[<tamaño_indice>];

Cuando se declara un arreglo, sus valores se pueden inicializar de la siguiente manera:

int lista[9]= {0,4,78,5,32,9,77,1,23}; /*Tiene valores en [0…8]*/

No trate de engañar al Compilador inicializando mas valores en el arreglo de los


que puede, ya que este no lo obedecerá, sin embargo, si inicializa solo una parte del
arreglo, las restantes posiciones se inicializan con ceros.

Si desea imprimir un valor de un arreglo, la línea luce así:

printf ("%d", lista[1]); /*Imprime el número: 4*/

Una Característica importante de los arreglos en C es que no se pueden


modificar los limites superior e inferior (y por tanto el rango) durante el programa. El
límite inferior se fija siempre en 0 y el superior lo fija el programador, es decir:

Se han visto hasta ahora, arreglos llamados Unidimensionales, pero existen


también los llamados Bidimensionales(o “matrices”), y se declaran así:

<tipo> <nombre_arreglo_bidimensional>[<tamaño_fila>][<tamaño_columna>];

Estos también son comúnmente conocidos como Matrices, El tamaño en la


declaración de la matriz estipula Renglón-Columna y se representarían así:

(85)
Estos también se pueden inicializar:

int lista_nueva[2][2]={{14, 34},{23, 67}};

Y se acceden de la misma manera que un unidimensional.

Ejemplo:

printf ("%d", lista_nueva[1][0]);

Y de esta forma se pueden construir arreglos Multidimensionales por ejemplo:

int grande[3][4][7];

ó incluso

int mas_grande [5][7][8][2][3][2];

pero se debe de tener cuidado al manejar estos arreglos por que son complejos
de manipular a la larga. A pesar de ser Bidimensionales, en la memoria siguen siendo
representados como espacios secuenciales lineales.

“Toda la memoria del computador, no es mas que una arreglo “megagigante” donde
se guardan todos los datos, por muy complejo que parezca su almacenamiento.”

Breve resumen sobre los arreglos: La Definición de arrays

Los arrays se inicializan con este formato:

int a[3] = {5, 10, 15};


char cad[5] = {‘a’, ‘b’ , c’, ‘d’, ‘e’};
int tabla [2][3] = {{l,2,3} {3,4,5}};

Las tres siguientes definiciones son equivalentes:

char saludo [5] = “hola”;


char saludo [] = “hola”;
char saludo [5] = {‘h’, ‘o’, ‘l’, ‘a‘}

1. Los arrays se pueden pasar como argumentos a funciones.

2. Las funciones no pueden devolver arrays.

3. No está permitida la asignación entre arrays. Para asignar un array a otro, se debe
escribir el código para realizar las asignaciones elemento a elemento.

(86)
Arreglos y Apuntadores.

A los arrays se accede a través de los índices:

int lista [5];


lista [3] = 5;

Las versiones con apuntadores en los arreglos son más rápidas que la
indexación común. La declaración:

int arr[10]; /*Se declara un arrays en C con diez elementos sin inicializar*/

int *pa,*ptr; /*se crean dos punteros a enteros*/

ptr = arr; /*fija puntero al primer elemento del array*/

ptr =+3; /* ptr = ptr + 3, suma 3 a ptr; ptr apunta al 4to elemento de arr*/

*ptr = 5; /*completa el 4to elemento de arr con valor 5.*/

/*El apuntador pa toma la dirección de memoria donde esta almacenado a[0]*/

pa=&a[0];

/*y así establecemos que:*/

/*pa apunta al valor almacenado en a[0]*/

*pa=a[0];

/*y*/

/*pa+1 apunta al valor almacenado en a[1]*/

*(pa+1)=a[1];

/*y así sucesivamente…*/

De esta manera se pude manejar mas eficientemente los valores y direcciones


de un arreglo Bi o Unidimensional.

El nombre de un array se puede utilizar también como si fuera un puntero al


primer elemento del array.
double a [10];
double *p = a; // p y a se refieren al mismo array.

(87)
M O Y

0 1 2 3 4 5 6 7 8 9

A este elemento se puede acceder por:

a[0] accede a M , *p ;o bien p[0]


a[5] accede a O, *(p + 5); o bien p[5]
a[9] accede a Y, *(p + 9); o bien p[9]

Si el nombre apunta al primer elemento del array, entonces nombre + 1 apunta


al segundo elemento. El contenido de lo que se almacena en esa posición se obtiene
por la expresión:*(<nombre_del_apuntador> + 1).

Aunque las funciones no pueden modificar sus argumentos, si un array se utiliza


como un argumento de una función, la función puede modificar el contenido del array.

Punteros a estructuras

Los punteros a estructuras son similares y funcionan de igual forma que los
punteros a cualquier otro tipo de dato.

struct familia
{
char marido[100];
char esposa[100];
char hijo[100];
}

familia Mackoy; //Mackoy estructura de tipo familia


struct familia *p; //p, un puntero a familia
p = &Mackoy; //p, contiene dirección de mackoy
strcpy (p->marido,“Luis Mackoy”); //inicialización
strcpy (p ->esposa, “Vilma Gonzalez”); //inicialización
strcpy (p ->hijo, “Luisito Mackoy”); //inicialización

Punteros a objetos constantes

Cuando se pasa un puntero a un objeto grande, pero se trata de que la función


no modifique el objeto (por ejemplo, el caso de que sólo se desea visualizar el
contenido de un array), se declara el argumento correspondiente de la función como
puntero a un objeto constante.
La declaración: const <NombreTDD> *v establece v como un puntero a un
objeto que no puede ser modificado. Un ejemplo puede ser:

void <nombre_función>(const <ObjetoGrande> *v);

(88)
Punteros a void

El tipo de dato void representa un valor nulo. En C++, sin embargo, el tipo de
puntero void se suele considerar como un puntero a cualquier tipo de dato. La idea
fundamental que subyace en el puntero void en C++ es la de un tipo que se puede
utilizar adecuadamente para acceder a cualquier tipo de objeto, ya que es más o
menos independiente del tipo. Un ejemplo ilustrativo de la diferencia de
comportamiento en C y C++ es el siguiente segmento de programa:

int main()
{
void *vptr;
int *iptr;
vptr = iptr;
iptr = vptr; //Incorrecto en C++, correcto en C
iptr = (int *) vprr; //Correcto en C++
}

Punteros y cadenas

Las cadenas en C++ se implementan como arrays de caracteres, como


constantes de cadena y como punteros a caracteres.

Constantes de cadena

Su declaración es similar a:

char *cadena = “Mi profesor”;

o bien su sentencia equivalente:

char varcadena[ ] = “Mi profesor”;

Si desea evitar que la cadena se modifique, añada const a la declaración:

const char *varcadena = “Mí profesor”;

Los puntos a cadena se declaran:

char s[1]; o bien: char *s;

Punteros a cadenas

Los punteros a cadenas no son cadenas. Los punteros que localizan el primer
elemento de una cadena almacenada.

char *varCadena;
const char *cadenafija;

(89)
Consideraciones prácticas

Todos los arrays en C++ se implementan mediante punteros:

char cadenal[l6] = “Concepto Objeto”;


char *cadena2 = cadenal;
Las declaraciones siguientes son equivalentes y se refieren al carácter
C’:
cadenal[0] = ‘a’;
char car = ‘a’;
cadena1[0] = car;

Los operadores NEW Y DELETE

C++ define un método para realizar asignación dinámica de memoria, diferente


del utilizado en mediante los operadores new y delete.
El operador new sustituye a la función malloc tradicional en C, y el operador
delete sustituye a la función free tradicional, también en C. new, asigna memoria, y
devuelve un puntero al new Nombre Tipo y un ejemplo de su aplicación es:

int *ptrl;
double *ptr2;
ptrl = new int; // memoria asignada para el objeto ptrl
ptr2 = new double; // memoria ampliada para el objeto ptr2
*ptrl = 5;
*ptr2 = 6.55;

Dado que new devuelve un puntero, se puede utilizar ese puntero para inicializar el
puntero de una sola definición, tal como:

int *p = new int;

Si new no puede ocupar la cantidad de memoria solicitada devuelve un valor


NULL. El operador delete libera la memoria asignada mediante new.

delete prt1;

Un pequeño programa que muestra el uso combinado de new y delete es:

include <iostream.h>
void main (void)
{
char *c;
c = new char[512];
cin >> c;
cout << c <<endl;
delete [] c;
}

(90)
Los operadores new y delete se pueden utilizar para asignar memoria a
arrays, clases y otro tipo de datos.

int *i;
i = new int[2][35]; //crear el array de 2 x 35 dimensiones
… //asignar el array
delete i; //destruir el array

Sintaxis de new y delete

new <nombre-tipo> new int new char[l00];


new <nombre-tipo> <ínicializador> new int (99) new char(’C’);
new <nombre-tipo> new (char*);
delete <expresión> delete p;
delete[] <expresión> delete []p;

ENUMERACIONES

En C++, un nombre de una enumeración, estructura o unión es un nombre de


un tipo. Por consiguiente, la palabra reservada struct, union, o enum no son
necesarias cuando se declara una variable.
El tipo de dato enumerado designa un grupo de constantes enteros con
nombres. La palabra reservada enum se utiliza para declarar un tipo de dato
enumerado o enumeración. La sintaxis es:

enum <nombre>{<valor_1>,<valor_2>,<valor_3>,…,<valor_n>};

Donde <nombre> es el nombre de la variable declarada enumerada, <valor> es una


lista de “tipos n-numerados”, a los que se asigna valores cuando se declara la variable
enumerada y puede tener un valor de inicialización. Se puede utilizar el nombre de una
enumeración para declarar una variable de ese tipo (variable de enumeración). Ej:
<nombre> <ver>;
Considérese la siguiente sentencia:

enum color [Rojo, Azul, Verde, Amarillo];

Una variable de tipo enumeración color es:

color pantalla = Rojo; //Estilo de C++

ESTRUCTURAS

Una estructura (o registro) es un tipo de dato compuesto que contiene una


colección de elementos de tipos de datos diferentes combinados en una única
construcción del lenguaje. Cada elemento de la colección se llama miembro y puede
ser una variable de un tipo de dato diferente. Una estructura representa un nuevo tipo
de dato en C++.

(91)
La sintaxis de una estructura es:

struct <nombre>{<miembro_1>;<miembro_2>;…;<miembro_n>};

La sintaxis para la composición de un miembro especifico, podría ser:

<miembro_n> = <TDD> <campo_n>

Un ejemplo y una variable tipo estructura se muestran en las siguientes sentencias:

struct cuadro
{
int i;
float f;
};
struct cuadro nombre; /*Estilo C cuadro es una variable del TDD cuadro*/

cuadro nombre; //Estilo C++

UNIONES

Una unión es una variable que puede almacenar objetos de tipos y tamaños
diferentes. Una unión puede almacenar tipos de datos diferentes, sólo puede
almacenar uno cada vez, en oposición a una estructura que almacena
simultáneamente una colección de tipos de datos. La sintaxis de una unión es:

union <nombre>{<miembro_1>,<miembro_2>,…,<miembro_n>};

Un ejemplo de una unión es:

union alfa
{
int x;
char o;
};

Una declaración de una variable estructura es:

alfa w;

El modo de acceder a los miembros de la estructura es mediante el operador punto ●.

Ejemplo:

u.x = 145;
u.c = ‘z’;

(92)
C++ admite un tipo especial de unión llamada unión anónima, que declara un
conjunto de miembros que comparten la misma dirección de memoria. La unión
anónima no tiene asignado un nombre y, en consecuencia, se accede a los elementos
de la unión directamente. La sintaxis de una unión anónima es:

union
{
int nuevolD;
int contador;
}

Las variables de la unión anónima comparten la misma posición de memoria y espacio


de datos.

int main()
{
union
{
int x;
float y;
double z;
}
x = 25;
y = 245.245; //el valor en y sobrescribe el valor de x
z = 9.41415; //el valor en z sobrescribe el valor de z
}

CADENAS EN C++

Una cadena es una serie de caracteres almacenados en bytes consecutivos de


memoria. Una cadena se puede almacenar en un array de caracteres (char) que tenían
en un carácter nulo (cero):

char perro[5] = { `m`,`o`,`r`,`g`,`a`,`n`}; // no es una cadena


char gato[5] = { ´f´,´e´,´l´,´i´,´n´,´o´,´\0´,}; // es una cadena

Lectura de una cadena del teclado

#include <iostream.h>
main ()
{
char cad [80];
cout << “introduzca una cadena:”; // lectura del teclado cm » cad;
cin >> cad;
cout << “Su cadena es:”;
cout << cad;
return 0;
}

(93)
Esta lectura del teclado lee una cadena hasta que se encuentra el primer
carácter blanco. Así, cuando se lee “Hola que tal” la primera cadena, en cad sólo se
almacena Hola. Para resolver el problema, utilizará la función gets () que lee una
cadena completa leída del teclado. El programa anterior quedaría así:

#include <iostream.h>
#include <stdio.h>
main()
{
char cad[80];
cout « “Introduzca una cadena:”;
gets (cad);
cout « Su cadena es:”; cout << cad;
return 0;
}

Definición de funciones

La definición de una función es el cuerpo de la función que se ha declarado con


anterioridad.

double Media (double x, double y) // Devuelve la media de x e y


{
return (x + y)/2.0
}
char LeerCaracter() //Devuelve un carácter de la entrada estándar
{
char c;
cin >> c;
return c;
}

Argumentos por omisión

Los parámetros formales de una función pueden tomar valores por omisión, o
argumentos cuyos valores se inicializan en la lista de argumentos formales de la
función.
int Potencia (int n, int k = 2);
Potencia(256); //256 elevado al cuadrado

Los parámetros por omisión no necesitan especificarse cuando se llama a la


función. Los parámetros con valores por omisión deben estar al final de la lista de
parámetros:

void fund (int i =3, int j); // no correcto


void func2 (int i, int j=0, int k = 0); // correcto
void func3 (int i = 2, int j, int k = 0); // no correcto
void ImprimirValores (int cuenta,double cantidad= 0.0);

(94)
Llamadas a la función ImprimirValores:

ImprimirValores (n,a);
ImprimirValores (n); //equivalente a ImprimirValores (n, 0.0)

Otras declaraciones y llamadas a funciones son:

double fl(int n, int m, int p=0); // correcto


double f2(int n, int m= 1, int p = 0); // correcto
double f3(int n = 2, int m= 1, int p =0); // correcto
double f4(int n, int m = 1, int p); // no correcto
double f5(int n = 2, int m, int p = 0); // no correcto

Funciones en línea (inline)

Si una declaración de función está precedida por la palabra reservada inline, el


compilador sustituye cada llamada a la función con el código que implementa la
función. Ejemplo:

inline int max(int a, int b)


{
if (a > b) return a;
return b;
}
main ()
{
int x = 5, y = 4;
int z = Max(x,y);
}

Los parámetros con valores por omisión deben entrar al final de la lista de
parámetros: Las funciones f1, f2 y f3 son válidas, mientras que las funciones f4 y f5 no
son válidas. Las funciones en línea (inline) evitan los tiempos suplementarios de las
llamadas múltiples a funciones. Las funciones declaradas en línea deben ser simples
con sólo unas pocas sentencias de programa; sólo se pueden llamar un número
limitado de veces y no son recursivas.

Ejemplo:

inline int abs(int i);


inline int min(int v1, int v2);
int mcd(int vl, int v2);

“Las funciones en línea deben ser definidas antes de ser llamadas.”

(95)
#include <iostream.h>
int incrementar (int I);
inline incrementar (int i)
{
i ++;
return i;
}
main (void)
{
int i = 0;
while (i < 5)
{
i = incrementar (i);
cout « “i es:”« i «endl;
}
}

Sobrecarga de funciones

En C++, dos o más funciones distintas pueden tener el mismo nombre. Esta
propiedad se denomina sobrecarga. Un ejemplo es el siguiente:

int max (int, int);


double max (double, double);

o bien este otro:

void sumar (char i);


void sumar (float j);

Las funciones sobrecargadas se diferencian en el número y tipo de argumentos,


o en el tipo que devuelven las funciones, y sus cuerpos son diferentes en cada una de
ellas.

(96)
Ejemplo:

#include <iostream.h>
void suma (char);
void suma (float);
main (void)
{
int i = 65;
float j = 6.5;
char c = ‘a’;
suma ( i );
suma ( j ) ;
suma ( c ) ;
}
void suma (char i)
{
cout << “Suma interior(char) “ <<endl;
}
void suma ( float j )
{
cout << “Suma interior (float) “<< endl;
}

El modificador <const>

Constantes:

En C++, los identificadores de variables/constantes se pueden declarar


constantes, significando que su valor no se puede modificar.

Esta declaración se realiza con la palabra reservada const.

const double PI= 3.11416;


const char BLANCO = ´ ´;
const double PI_EG = -I;
const double DOBLE_I = 2 * PI ;

El modificador de tipos const se utiliza en C++ para proporcionar protección de


sólo lectura para variables y parámetros de funciones. Cuando se hace preceder un
tipo de argumento con el modificador const para indicar que este argumento no se
puede cambiar, el argumento al que se aplica no se puede asignar un valor ni cambiar.

void copia (const char *fuente, char *destino);


void funciondemo (const int I);

(97)
Paso de parámetros a funciones

En C++ existen tres formas de pasar parámetros a funciones:

1. Por valor La función llamada recibe una copia del parámetro y este
parámetro no se puede modificar dentro de la función

void intercambio (int x, int y)


{
int aux = y;
y = x;
x = aux;
}
//.....
intercambio (i , j ); // las variables i, j, no se intercambian

2. Por dirección. Se pasa un puntero al parámetro. Este método permite simular


en C/C++ la llamada por referencia, utilizando tipos punteros en los parámetros
formales en la declaración de prototipos. Este método permite modificar los
argumentos de una función.

void intercambio (int *x,int *y)


{
int aux = *y;
*y = *x
*x = aux;
}
// ...
intercambio (&i, &j); // i , j se intercambian sus valores

3. Por referencia. Se pueden pasar tipos referencia como argumentos de


funciones, lo que permite modificar los argumentos de una función.

void intercambio(int &x, int &y)


{
int aux = y;
y = x;
x = aux;
}
//.....

intercambio (i,j); // i , j intercambian sus valores

Si se necesita modificar un argumento de una función en su interior, el


argumento debe ser un tipo de referencia en la declaración de la función.

Paso de arrays

Los arrays se pasan por referencia. La dirección del primer elemento del array
se pasa a la función; los elementos individuales se pasan por valor. Los arrays se
pueden pasar indirectamente por su valor si el array se define como un miembro de
una estructura.
(98)
Ejemplo 1:

Paso del array completo.

#include <iostream.h>
void func1 (int x[]); //prototipo de función
void main( )
{
int a[3] = {l,2,3};
func1 (a) ; // sentencias
func1 (&a[0]) ; // equivalentes
}
void func(int x[])
{
int i;
for (i = 0; 1 < 3; i + 1)
cout << 1 << x[i]<< ‘\n’;
}

Ejemplo 2:

Pasa de a un elemento de un array.

#include <iostream.h>
const int n + 3;
void func2(int x);
void main( )
{
int a[n] = {l,2,3};
func2 (a[2]);
}
void func2(int x)
{
cout << x << ‘\n’;
}

(99)
Tamaño de un TDD (El operador: sizeof)

El operador (funsión) sizeof proporciona el tamaño en bytes de un tipo de dato


o variable sizeof toma el argumento correspondiente (tipo escalar, array, record, etc.).

La sintaxis del operador es:

sizeof (<nombre variable>); /*si se quiere saber el tamaño en byte de una


variable*/
sizeof (<tipo de dato>); /*si se quiere saber el tamaño de un tipo de dato
elemental*/

Ejemplos:

int m , n[12];
sizeof(m); // retorna 4, en maquinas de 32 bits
sizeof(n); // retorna 48, 4 byte x 12 posiciones
sizeof (15); // retorna 4 un entero 15
sizeof (int); // retorna el tamaño en memoria de un int (generalmente 32
bits). */

La sentencia nula:

La sentencia nula se representa por un punto y coma, y no hace ninguna


acción:

char cad[80]=”Cazorla”;
int i;
for (i = 0; cad[i] != ‘\0’; i++);

(100)
Prioridad y asociatividad de operadores en C (versión completa)

Cuando se realizan expresiones en las que se mezclan operadores diferentes es preciso


establecer una precedencia (prioridad) de los operadores y la dirección (o secuencia) de
evaluación (orden de evaluación: izquierda-derecha, derecha-izquierda), denominada
asociatividad. La Tabla B.11 muestra la precedencia y asociatividad de operadores.

Ejemplo:

a * b/c+d equivale a: (a * b ) / ( c + d )

Sobrecarga de operadores

La mayoría de los operadores de C++ pueden ser sobrecargados o redefinidos para trabajar con nuevos tipos de
datos.

Precedencia y asociatividad de operadores

:: ( ) [ ] . -> Izquierda-Derecha
++ -- Derecha-Izquierda
& (dirección) ~ (tipo) ¡ - +
sizeof (tipo) new delete * (indireccion)
.* ->* Izquierda-Derecha
*/% Izquierda-Derecha
+— Izquierda-Derecha
<< >> Izquierda-Derecha
< <= > >= Izquierda-Derecha
= = ¡= Izquierda-Derecha
& Izquierda-Derecha
^ Izquierda-Derecha
| Izquierda-Derecha
&& Izquierda-Derecha
|| Izquierda-Derecha
= += - = *= /= %= >>= <<= &= |= ^= Derecha-Izquierda
, (operador coma) Izquierda-Derecha

Operadores que se pueden sobrecargar

+ - * / % ^ & | ~ ! = < > >> << >>= <<= != == ( ) -> , []

(101)
ENTRADAS Y SALIDAS BÁSICAS

Al contrario que muchos lenguajes, C++ no tiene facilidades incorporadas para


manejar entrada o salida. En su lugar, se manejan por rutinas de bibliotecas. Las
clases que C++ utiliza para entrada y salida se conocen como flujos. Un flujo (stream)
es una secuencia de caracteres junto con una colección de rutinas para insertar
caracteres en flujos (a pantalla) y extraer caracteres de un flujo (de teclado).

Salida

El flujo cout es el flujo de salida estándar que corresponde a stdout en C. Este flujo se
deriva de la clase ostream construida en iostream.

CPU cout pantalla

Entrada binaria Salida de caracteres

Uso de flujos para salida de caracteres.

Si se desea visualizar el valor del objeto int llamado i, se escribe la sentencia:

cout << i;

El siguiente programa visualiza en pantalla una frase:

#include <iostream.h>
int main()
{
cout << “Hola Mundo\n”;
}

Las salidas en C++ se pueden conectar en cascada, con una facilidad


de escritura mayor que en C.

#include <isostrean.h>.
int main()
{
int i;
i = 1099;
cout << ”El valor de i es” << i << “\n”;
}

Otro programa que muestra la conexión en cascada es:

#include <iostream.h>
int main(){
int x = 45;
double y = 496.125;
char *c = "y es multiplicada por x=";
cout << c << y * x << "\n”;
}

(102)
Entrada

La entrada se maneja por la clase istream. Existe un objeto predefinido


istream, llamado cin, que se refiere al dispositivo de entrada estándar (el teclado). El
operador que se utiliza para obtener un valor del teclado es el operador de extracción
>>. Por ejemplo, si i era un objeto int, se escribirá:

cin >> i;

que obtiene un número del teclado y lo almacena en la variable i.


Un programa simple que lee un dato entero y lo visualiza en pantalla es:

#include <iostream.h>
int main()
{
int i;
cin >> i;
cout << i;
}

Al igual que en el caso de cout, se pueden introducir datos en cascada:

#include <iostream.h>
int main()
{
char c[60];
int x,y;
cin >> c >> x >> y;
cout << c << “ “ << x << “ “ << y << “\n”;
}
Manipuladores

Un método fácil de cambiar la anchura del flujo y otras variables de formato es


utilizar un operador especial denominado manipulador. Un manipulador acepta una
referencia de flujo como un argumento y devuelve una referencia al mismo flujo.

El siguiente programa muestra el uso de manipuladores específicamente para


conversiones de número (dec, oct, y hex):

#include <iostream.h>
int main ()
{
int i = 36;
cout << dec << i << oct << i << “ ” << hex << i << “\n”;
}

La salida de este programa es: 36 44 24

(103)
Otro manipulador típico es endl, que representa al carácter de nueva línea
(salto de línea), es equivalente a \n . El programa anterior
se puede escribir también así:

#include <iostream.h>
int main ()
{
int i = 36;
cout << dec << i << oct << i << hex << i << endl;
}

(104)
Palabras reservadas de C++

Las palabras reservadas o claves no se deben utilizar como identificadores,


debido a su significado estricto en C++; tampoco se deben redefinir. La Tabla enumera
las palabras reservadas de C++ según el ARM(Siglas del libro de BJARNE
STROUSTRUP en el que se definen las reglas de sintaxis del lenguaje C++ estándar).
Palabras reservadas de C++
asm* continue float new* signed try
auto default for operator* sizeof typedef
break delete* friend* private* static union
case do goto protected* struct unsigned
catch* double if public* switch virtual*
char else inline* register template* void
class* enurn int return this* volatile
const extern long short throw* while

*Estas palabras no existen en ANSI C.

Los diferentes compiladores comerciales de C++ pueden incluir, además, nuevas


palabras reservadas. Estos son los casos de Borland, Microsoft y Sysmantec.
Tabla. Palabras reservadas de Turbo/Borland C++
asm _ds interrup short
auto else _loadds signed
break enum long sizeof
case _es _near _ss
catch export near static
_cdecl extern new struct
_cdecl far operator switch
char far pascal template
class float pascal this
const for private typedef
continue friend protected union
_cs goto public unsigned
default huge register virtual
delete if return void
do inline _saveregs volatile
_double int _seg while

Tabla. Palabras reservadas de Microsoft Visual C/C++ 1.5/2.0


asm else int signed
auto enum _interrupt sizeof
based _except _leave static
break _export _loadds _stcall
case extern long struct
_cdecl _far maked switch
char _fastcall _near thread
const _finally _pascal _try
continue float register typedef
_declspec for return union
default _fortran _saveregs unsigned
dllexport goto _self void
dllimport _huge _segment volatile
do if _segname while
double _inline short
El comité ANSI ha añadido nuevas palabras reservadas (Tabla B.4).
Tabla. Nuevas palabras reservadas de ANSI C++
bool false reinterpretcast typeid
cons_cast mutable static_cast using
dynamic_cast namespace true wchart
(105)
Laboratorio #1 de C
Objetivos:

> Entender la sintaxis de C (tipos de datos básicos, condicionales, iteradores,


funciones y métodos, palabras claves, instrucciones de preprocesador) y hacer uso de
ella para desarrollar programas.
> Compilar un programa en C/C++ por medio del compilador de GNU gcc/g++
(Linux).
> Usar la librería stdio.h para procesar flujos de entrada y salida.
> Usar tipos de datos estructurados como arreglos, matrices, cadenas, y tipos
de datos definidos por el usuario.
> Aprender a usar Punteros.

1) Sintaxis de C
La sintaxis de C ha sido muy popular incluso en los tiempos modernos, existen
lenguajes que han heredado esta sintaxis (como Java), ya que es fácil de usar y
permite desarrollar aplicaciones grandes.

A) Tipos de datos básicos:

C posee los mismos tipos de datos primitivos que Java, estos son int, float,
char, bool*, double.

Los int pueden recibir valores constantes como números:


int x = 123;

También puede recibir valores octales o hexadecimales Octal:


int x = 0235; // asigna el valor 157 en octal (se antecede con un 0).

Hexadecimal:
int x = 0xAA; /* asigna el valor 170 en hex (se antecede con un 0x)*/

Los float pueden recibir valores constantes como:


float x = 0.587; /* para asignar valores de punto flotante se debe
usar “.” (punto)*/

También se puede lograr con notación exponencial


float x = 2E4; // esto equivale a 2 x 10^4

Los char reciben constantes entre comillas simples:


char x = 'a';

También pudieran recibir números enteros, ya que los char son enteros de 1
byte. El valor que va a tener este char va a ser el caracter cuyo código ASCII
corresponda con el número dado. Ejemplo:
char x = 48; // x va a tener el valor '0'.

* Igual al boolean de java, solo es usado en C++. C usa enteros como booleanos, si se
evalúa una condición que da como resultado 0 se tomaría como un false, en cualquier
otro caso es true.

(106)
B) Condicionales e iteradores:

Los condicionales e iteradores son exactamente iguales a los de Java, tenemos:

if
if - else
switch(expresión) – case value:
while
do – while(condición)
for

C) Palabras claves:

Las palabras claves, son exactamente las mismas que se pueden usar en
Java.

break: Usada para salir de un bloque iterativo (for, while, etc).

continue: Usada para ignorar todas las instrucciones en el bloque que se encuentran
después de esta instrucción.

D) Instrucciones de Preprocesador:

Las instrucciones de preprocesador son aquellas usadas para indicar


instrucciones al compilador. Algunas de estas instrucciones son:

#include: Se encarga de incluir una librería en el código actual


Ejemplo: #include “stdio.h”;

#define NOMBRE VALOR: Se encarga de definir una constante cuyo nombre es el


indicado en NOMBRE con el valor indicado en VALOR
Ejemplo: #define PI 3.14;

#ifdef - #else - #endif: Se encarga de verificar si la constante se encuentra definida,


funciona como un if, en el caso de que la constante exista se compilan las
instrucciones que están entre esta etiqueta y la etiqueta #endif.
Ejemplo:

#ifdef PI
int cualquiera;
#else
int cualquiera2;
#endif

También existe una variante de #ifdef llamada #ifndef, que funciona de manera
inversa a la antes mencionada.

(107)
E) Funciones y Métodos

En C las funciones son exactamente iguales a las de Java. Para definir un


método:
void acción(int <parametro1>) { /*hace algo*/ }

Para definir una función:

int sumar(int uno, int dos) { return uno + dos; }

Ejercicio:
***Desarrollar una función factorial (recursiva) en C.***

2) Compilar un programa con gcc/g++

Para compilar un código fuente de C, usamos por medio de la consola los


comandos gcc ó g++. La instrucción básica para compilar es:

gcc -o Factorial Factorial.c

En el caso de que queramos compilarlo con g++, cambiamos el gcc por


un g++ y funcionará de la misma manera.

-lbiblioteca

Liga con las bibliotecas objeto. Esta opción deberá seguir los argumentos de los
archivos fuente. Las bibliotecas objeto son guardadas y pueden estar estandarizadas,
un tercero o usuario las crea. Probablemente la biblioteca más comúnmente usada es
la biblioteca matemática (math.h). Esta biblioteca deberá ligarse explícitamente si se
desea usar las funciones matemáticas (y por supuesto no olvidar el archivo cabecera
#include <math.h>, en el programa que llama a las funciones) por ejemplo:

gcc Factorial.c -o Factorial -lm

Muchas otras bibliotecas son ligadas de esta forma.

-Ldirectorio

Agrega directorios a la lista de directorios que contienen las rutinas de la


biblioteca de objetos. El ligador siempre busca las bibliotecas estándares y del sistema
en /lib y /usr/lib. Si se quieren ligar bibliotecas personales o instaladas por usted, se
tendrá que especificar donde están guardados los archivos. Por ejemplo:

gcc Factorial.c -L/home/minombr/mislibs milib.h

-Itrayectoria

Agrega una trayectoria o ruta a la lista de directorios en los cuales se buscarán


los archivos cabecera #include con nombres relativos (es decir, los que no empiezan
con diagonal /). El procesador por default, primero busca los archivos #include en el
directorio que contiene el archivo fuente, y después en los directorios nombrados con
la opción -I si hubiera, y finalmente, en /usr/include.
(108)
-g3

Compila el código, de tal manera que el ejecutable va a tener la suficiente


información como para poder ser depurado. Por ejemplo:

gcc Factorial.c -o Factorial -g3

3. Uso de la librería stdio.h

Una de las facultades de C, es la facilidad para manejar los flujos de entrada y


salida.
C posee dos funciones básicas pero poderosas para imprimir en un flujo de
salida y para leer de un flujo de entrada.

Para imprimir: fprintf()

Parámetros:
• Flujo al cual va a imprimir (puede ser la salida estándar (consola) o a un
archivo).
• Recibe una cadena la cual puede tener expresiones que pueden ser
sustituidas.
• Puede recibir las diferentes variables para cumplir el formato dado en la
cadena inicial.

Ejemplo:

fprintf (STDOUT, “Vamos a imprimir un entero: %d\n”,15);

Para leer: fscanf()

Parámetros:

• Flujo del cual se va a leer (puede ser la entrada estándar (consola) o a un


archivo).
• Recibe una cadena la cual puede tener expresiones que se van a leer.
• Puede recibir las diferentes variables para cumplir el formato dado en la
cadena inicial.

Ejemplo:
int variable = 0;
fscanf(STDIN,”%d”,&variable);

Los Parámetros que se pueden pasar en la cadena de formato pueden ser:

• %d para entero
• %f para flotantes
• %c para caracteres
• %s para cadenas
• %lf para doubles
• %llf para long long

(109)
Ambas funciones devuelven un entero, el cual indica en el caso de fprintf el
número de caracteres impresos, y en el caso de fscanf el número de parámetros que
fueron leídos.

4. Tipos de datos estructurados

Como cualquier otro lenguaje, C ofrece distintos tipos de datos estructurados como lo
son arreglos, y tipos de datos definidos por el usuario.

A) Arreglos:

Los Arreglos se definen de la siguiente manera:

int arreglo[<tamaño>];

Los arreglos pueden ser definidos con cualquier tipo de dato. Incluso los definidos por
el usuario.

NOTA: vale la pena acotar que cuando se crean los arreglos, los valores contenidos en
el mismo no se encuentran inicializados, normalmente ningún tipo de dato en C va a
tener un valor de inicializado por defecto.

Las Matrices se definen de la siguiente manera:

float matrix[<N_FILAS>][<N_COL>];

Para definir cadenas, usamos arreglos de caracteres, a diferencia de Java, C no posee


ningún objeto “string”. Solo arreglos de caracteres.

char cadena[<TAMAÑO>];

Para definir nuestros propios tipos de datos, usamos la sentencia struct.

struct Persona {
int cedula;
char nombre[20];
};

Esta sentencia solo va a crear una persona, para que se pueda usar como tipo
de dato tenemos que usar la sentencia typedef antes del struct.

typedef struct {
int cedula;
char nombre[20];
} Persona;
Persona pepe;

(110)
5. Definir Apuntadores

En C a diferencia de Java nosotros podemos usar directamente los apuntadores


que hacen referencias a los tipos de datos. Se pueden crear apuntador para cada tipo
de dato, incluso los definidos por el programador.
Para definir un apuntador de Persona, se puede hacer de la siguiente manera:

Persona persona1;
Persona ptr*;
ptr = &persona1;

Para acceder a las propiedades de persona por medio del apuntador puede
usarse el operador de dereferenciación (->)

int cedula = ptr->cedula;

(111)
Laboratorio #2 de C

– Archivos en C, Listas simples y C++ básico

1. Manejo de archivos en C / C++.

C ve cada archivo simplemente como un flujo secuencial de bytes. Cada archivo


termina con una marca de fin de archivo o con un número de bytes especifico
almacenado dentro de una estructura de datos administrada y mantenida por el
sistema.
Al abrir un archivo se devuelve un apuntador a la estructura FILE la cual
contiene la información necesaria para procesar el archivo.

1.1 Creación de un archivo de acceso secuencial.

Para referenciar un archivo se crea un apuntador a la estructura FILE la cual


posteriormente se asocia a un archivo.

FILE *puntero; /* Se crear una variable puntero la cual es un apuntador a un


archivo*/

1.2 Apertura de un archivo.

Una vez declarado un puntero a archivo utilizaremos la función fopen(). Para abrir
el archivo y asociarlo al puntero.

Su sintaxis es:

puntero = fopen ( nombre del archivo, "modo de apertura" );

Donde puntero es la variable de tipo FILE, nombre del archivo es el nombre


que daremos al archivo que queremos crear o abrir. Este nombre debe ir encerrado
entre comillas. También podemos especificar la ruta donde se encuentra o utilizar un
arreglo que contenga el nombre del archivo (en este caso no se pondrán las comillas).

Algunos ejemplos:

puntero = fopen("DATOS.DAT","r");
puntero = fopen("C:\\TXT\\SALUDO.TXT","w");

Un archivo puede ser abierto en dos modos diferentes, en modo texto o en


modo binario. A continuación lo veremos con más detalle.

Modo texto

w crea un archivo de escritura. Si ya existe lo crea de nuevo.


w+ crea un archivo de lectura y escritura. Si ya existe lo crea de nuevo.
a abre o crea un archivo para añadir datos al final del mismo.
a+ abre o crea un archivo para leer y añadir datos al final del mismo.
r abre un archivo de lectura.
r+ abre un archivo de lectura y escritura.
(112)
Modo binario

wb crea un archivo de escritura. Si ya existe lo crea de nuevo.


w+b crea un archivo de lectura y escritura. Si ya existe lo crea de nuevo.
ab abre o crea un archivo para añadir datos al final del mismo.
a+b abre o crea un archivo para leer y añadir datos al final del mismo.
rb abre un archivo de lectura.
r+b abre un archivo de lectura y escritura.

La función fopen devuelve, como ya hemos visto, un puntero de tipo FILE. Si


al intentar abrir el archivo se produjese un error (por ejemplo si no existe y lo estamos
abriendo en modo lectura), la función fopen devolvería NULL. Por esta razón es mejor
controlar las posibles causas de error a la hora de programar.

Un ejemplo:

FILE *pf;
pf=fopen("datos.txt","r");
if (pf == NULL) printf("Error al abrir el archivo");

1.3 Cierre de un archivo

Una vez que hemos acabado nuestro trabajo con un archivo es recomendable
cerrarlo. Los archivos se cierran al finalizar el programa pero el número de estos que
pueden estar abiertos es limitado. Para cerrar los archivos utilizaremos la función
fclose( );.

Esta función cierra el archivo, cuyo puntero le indicamos como parámetro. Si el


archivo se cierra con éxito devuelve 0.

fclose(puntero);

Un ejemplo ilustrativo es:

FILE *pf;
pf = fopen("AGENDA.DAT","rb");
if ( pf == NULL )
printf ("Error al abrir el archivo");
else
fclose(pf);

1.4 Lectura desde un archivo

Existen muchas maneras de lectura desde un archivo aquí se mencionaran las


mas básicas y de fácil uso la primera de estas es fgetc ().

Para leer un carácter

int fgetc (FILE *stream);


char c;
c = fgetc (<puntero>); /* Obtiene el próximo carácter de un stream.*/
(113)
Esta Función retorna el próximo carácter de un stream el cual esta siendo
referenciado por puntero el cual es un apuntador a un archivo abierto.

Ejemplo contador del número de líneas de un archivo

do {
c = fgetc (pFile);
if (c == '\n') i++;
} while (c != EOF);

Leer una Estructura:

int fread (void *buffer, size_t size, size_t count, FILE *stream);

Lee un Bloque de datos desde un stream.

Lee un numero count de intems cada uno de un tamaño size en bytes desde un stream
y los almacena en un buffer.

El puntero al stream se incrementa según el numero de bytes leídos, el total debe ser
(size x count);

Parámetros…

buffer
Apuntador a la estructura de destino con un tamaño mínimo de (size *count) byte.
size
Tamaño en bytes para cada intems a ser leído.
count
Numero de intems a ser leídos, cada uno con tamaño size en bytes.
stream
Apuntador a un archivo abierto.

Valor devuelto.

El número total de intems leídos, si el número es diferente a count ocurre un


error.

1.5 Escritura en un archivo.

Escribir un carácter

int fputc (int character, FILE *stream);

Escribe un carácter en un stream, lo escribe en la posición actual del stream y


el apuntador se mueve al siguiente carácter.

(114)
Parámetros

carácter
Carácter a ser escrito, si es un entero se escribe como entero sin signo.

stream
Apuntador a un archivo abierto.

Escribir estructuras

size_t fwrite(const void *buffer,size_t size,size_t count,FILE *stream );

Escribir un bloque de datos en un stream.

Escribe un numero count de intems, cada uno de tamaño size en bytes, desde
la memoria apuntada por buffer, en la posición actual del stream.

Parámetros.

buffer
Apuntador a la data a ser escrito.

size
Tamaño de cada uno de los intems a ser escritos.

count
Número de intems a ser escritos, cada uno de tamaño size en bytes.

stream
Apuntador a archivo abierto con permiso de escritura.

NOTA: También se pueden usar las funciones fscanf y fprintf dadas en


el laboratorio anterior.

2. Sintaxis C++

La sintaxis de C++ hereda todas las de C, pero también incluye soporte de


clases, tipos de datos (bool), etc.
A continuación veremos como declarar Clases en C++

(115)
2.1 Clases

Las Clases en C++ se declaran de la siguiente forma:

class <NombreDeLaClase> [: public <ClasePadre>] {


private: // <-- modificador de acceso
tipo_dato <atributo1>;
tipo_dato <atributo2>;
public:
int <metodo1>(int <param>); // método no inline
void <metodo2>() { // método inline
//algun cuerpo ...
}static void <metodo3>() { // método estático
// algo...
}
};

Como pudimos ver en el ejemplo, la declaración de los atributos de la clase va a ser como
el de cualquier estructura en C.

Para los métodos existen 3 tipos de declaraciones: los inline, los normales y los
estáticos.

Inline: son aquellos métodos que funcionan como macros, es decir, la llamada
a el método va a ser sustituida por el código que se encuentra dentro de ese método
(esta sustitución va a estar dada en el código ejecutable).

Static: los métodos estáticos (o de clase) son aquellos que serán invocados sin
tener que crear un objeto (instancia de la clase). Estas normalmente no alteraran el
estado de la clase. Estas pueden ser invocadas usando: Clase.metodo(); .

Normales: los métodos normales son aquellos que son declarados en la clase,
pero son definidos fuera de ella. Estos se comportarían de la manera que se espera,
cuando se invoca a un método normal, se crea un nuevo ambiente de ejecución para
este método, una vez que finalice es eliminado.

Para poder definir un método normal fuera de la clase se debe usar el operador
de referenciación “::”. Por ejemplo asumiendo que se declaro la clase
“NombreDeLaClase”, para definir el “metodo1”, se hace de la siguiente manera:

int <NombreDeLaClase>::<metodo1>(int <param>) {


// hacer algo
return 0;
}

(116)
Modificadores de Acceso (MDA)

Los modificadores de acceso permiten aplicar el concepto de “ocultamiento de


información” del paradigma de la programación orientada a objetos. Estos aparecen en
orden decreciente de visibilidad. Este puede ser asociado con un atributo o función
anteponiendo las palabras reservadas public, protected, private, seguidos del
símbolo “:”. Por defecto las clases tienen un modificador de acceso private, por eso
cuando se desee declarar métodos públicos en la clase, estos deben ser precedidos por
la sentencia public:.

Herencia

Por poder hacer uso de la herencia en C++, cuando se declara la clase se debe
especificar cual es su clase padre con:
“ : (public|protected|private) ClasePadre “

En la herencia también se pueden aplicar los modificadores de acceso, pero


sigue un lineamiento un poco distinto.
Si el modificador es public, todos los métodos del padre que sean public o
protected se mantendrán con ese mismo modificador de acceso en la clase hija. Si el
modificador es protected, todos los métodos del padre que sean public o protected,
serán declarados como protected en la clase hija.
Si el modificador es private, todos los métodos del padre que sean public o
protected, serán declarados como private en la clase hija.

3. Listas simples.

Una lista es una colección finita de elementos del mismo tipo, ordenados de
acuerdo a su posición en la lista, para el estudios de listas en C++ se implementara de
manera dinámica (crece según sea necesario).
El TDA (Tipo de Dato Abstracto) listas implementa varias operaciones las cuales
en la practica podemos modificar a conveniencia.
Entre los métodos se pueden tener:

agregar(nuevoElemento)
obtener(indice)
eliminar(indice)
tamaño()
entre otros...

Las Listas pueden ser definidas como un TDA o como una Clase, la diferencia
principal es que, si se define como clase, todos los métodos van a estar contenidos en
la clase o estos van a modificar el estado interno del objeto de la clase.

Ejemplo de implementación con clases:

Lista *l = new Lista();


l->agregar(nuevoElemento);

(117)
Los métodos invocados pertenecen al objeto y modifican el estado del objeto.

Ejemplo de implementación con TDA:

Lista l;

agregar(l,nuevoElemento);

En cada invocación de método debe ser agregada la lista para que ésta pueda
ser modificada. Cualquiera de los dos enfoques es válido.

3.1 Asignación dinámica de memoria.

NOTA: El Operador sizeof (variable), es una función que proporciona el


lenguaje C para determinar el tamaño en bytes de una variable.

Estas funciones permiten obtener espacios de memoria en tiempo de ejecución


para almacenar nuevos nodos y liberar la misma cuando no sea necesario.

void *malloc ( size_t siz e );

La función malloc tiene como parámetro el número de bytes necesarios para la


asignación de memoria dinámica, retorna un apuntador a un bloque de memoria con el
tamaño solicitado.
Como el tipo de dato devuelto es void * , se le puede asignar a cualquier
apuntador, comúnmente la función malloc se utiliza junto a la función sizeof la cual
retorna el numero de bytes necesarios para una variable.

Nombretipo *ptrNuevo;
ptrNuevo = malloc (sizeof(nombretipo));
void free (void *memblock)

La Función free libera un bloque de memoria previamente reservado.

Free (ptrNuevo);

3.1 Asignación de memoria dinámica con POO

Para la programación orientada a objetos se utiliza el operador new(), este


operador crea un objeto del tamaño indicado, llamada constructor para el objeto y
retorna un apuntador del tipo correcto.

prtNuevo = new nombretipo;

Para la liberación de memoria de manera dinámica se utiliza el operador delete().

delete PrtNuevo

(118)
Actividad nro 1.

Utilice clases para la Implementación:

Dado el archivo info.txt el cual contiene la información de productos se desea


que usted plantea una estructura de datos para almacenar la información de dicho
producto y luego implemente la clase lista con las operaciones InsertarOrdenado() y
EliminarOrdenado() , para dicha estructura.

Una vez creada estas funciones desde la acción principal se va a ir leyendo la


información desde el archivo para cada producto y se va a insertar en una lista de
productos la cual debe estar ordenada por código de producto.

Una vez generada la lista se debe dar las opciones de: Eliminar un producto,
Mostrar estado de la lista, Salir de la aplicación, la aplicación debe funcionar hasta que
se elija salir, para eliminar un producto se debe solicitar el código del mismo y la lista
debe quedar ordenada.
Formato del archivo info.txt

Cada línea contiene la información de un producto, primero el código el cual es


un entero de 3, luego la descripción, la cual es una cadena de caracteres de máximo
20 letras, y el precio entero, entre cada valor hay un espacio en blanco.

<código> <espacio> <descripción> <espacio> <precio>

10 cdrom 85000
15 floppy 30000
2 monitor 350000

(119)
Sentencias de salto:

Sentencias break, continue, goto

La instrucción break interrumpe la ejecución del bucle donde se ha incluido,


haciendo al programa salir de él aunque la expresión_de_control correspondiente a
ese bucle sea verdadera

La sentencia continue hace que el programa comience el siguiente ciclo del


bucle donde se halla, aunque no haya llegado al final de las sentencia compuesta o
bloque.

La sentencia goto <etiqueta>(es el salto incondicional en ensamblador), hace


saltar al programa a la sentencia donde se haya escrito la etiqueta correspondiente.
Por ejemplo:

Sintaxis:

sentencias …

if(condición)

goto salto;
sentencia_1;
sentencia_2;

}
salto:
sentencia_3;
sentencia_4;

La palabra bucle es sinónimo de ciclo.

Para más información sobre break y continue consulte la página 140 de ciclos
infinitos de C++.

Obsérvese que la etiqueta termina con el carácter (:). La sentencia goto no es


una sentencia muy prestigiada en el mundo de los programadores de C++, pues
disminuye la claridad y legibilidad del código. Fue introducida en el lenguaje por
motivos de compactibilidad con antiguos hábitos de programación, y siempre puede
ser sustituida por otras expresiones más claras y estructuradas.

(120)
SOBRE ALGUNOS OPERADORES:

Operador coma(,)

Los operandos de este operador son expresiones, y tiene la forma general:

expresión = expresión_1, expresión_2;

Es este caso, expresión_1 se evalúa primero, y luego se evalúa expresión_2.


El resultado global es el valor de la segunda expresión, es decir de expresión_2.Este
es el operador de menos precedencia de todos los operadores de C++.

Operadores new y delete

Hasta ahora sólo se ha visto dos posibles tipo de duración de las variables:
static, las cuales existen durante toda la ejecución del programa, y automatic, que
existen desde que son declaradas hasta que finaliza el bloque donde han sido
declaradas.

Con los operadores new y delete el programador tiene entera libertad para
decidir crear o destruir variables cuando las necesite. Una variable creada con el
operador new dentro de cualquier bloque, perdura hasta que es explícitamente
borrada con el operador delete. Puede traspasar la frontera de su bloque y ser
manipulada por instrucciones de otros bloques.

Estos operadores serán descritos mas ampliamente en el apartado dedicado a la


reserva dinámica de memoria.

Operador de resolución de visibilidad (::)

Este operador permite acceder a una variable global cuando ésta se encuentra
oculta por otra variable local del mismo nombre. Considérese el siguiente ejemplo:

int a=2;

void main(void){
int a = 10;
cout << a << endl; //muestra por pantalla 10
cout << ::a << endl; //muestra por pantalla 10
}

OPERADOR CONDICIONAL (el ?:)

También conocido como operador opcional. Este operador permite controlar el


flujo de ejecución del programa.

El operador condicional es un procesador con tres operandos (ternario) que


tiene la siguiente forma general:

expresión_1 ? expresión_2 : expresión_3;

(121)
Explicación: Se evalúa la expresión_1. Si el resultado de dicha evaluación es
trae (!=0), se ejecuta la expresión_2; si el resultado es false(=0), se ejecuta
expresión_3.

Los backward_warning.h o warning de C

A veces el programa C/C++ suele enviarnos estas clase de mensajes o


capciones lo que muchas veces nos alarma, lo que indican esta clase de mensaje
“warning” es que no estamos usando alguna variable, por lo que si nos aparece
recomiendo encarecidamente que se ordene compilar y ejecutar el programa en contra
de todo lo que se piense. Los warning no son errores como tales.

(122)
Estructuras de almacenamiento:

Manejos de arreglos apuntadores

Una estructura es una forma de agrupar un conjunto de datos de distinto tipo


bajo un mismo nombre o identificador. Por ejemplo, supóngase que se desea diseñar
una estructura que guarde los datos correspondientes a un alumno de primero. Esta
estructura, a la que se llamará alumno, deberá guardar el nombre, la dirección, el
número de matrícula, el teléfono, y las notas en las 10 asignaturas. Cada uno de estos
datos se denomina miembro de la estructura.
El modelo o patrón de esta estructura puede crearse del siguiente modo:

Programa:

struct alumno
{
char nombre[31];
char direccion[21];
unsigned long no_matricula;
unsigned long telefono;
float notas[10];
};

El código anterior crea el TDD alumno (“plantilla registro de nombre alumno”),


pero aún no hay ninguna variable declarada con este nuevo tipo. De hecho este bloque
se declara fuera del main, además la necesidad de incluir un carácter (;) después de
cerrar las llaves. Este tipo de declaración ahorra complejidad en memoria ya que ni
siquiera sus campos ocupan espacio en memoria, a menos que se empiecen a crear
nodos o listas. Luego para declarar dos variables de tipo alumno se debe utilizar la
sentencia:

Programa:

alumno alumno1, alumno2;

donde tanto alumno1, como alumno2 son una estructura, la cual hereda la
forma de la plantilla alumno, que podrá almacenar un nombre de hasta 30 caracteres
c/u, una dirección de hasta 20 caracteres c/u, el número de matrícula, el número de
teléfono y las notas de las 10 asignaturas. También podrían haberse definido alumno1
y alumno2 al mismo tiempo que se definía la estructura de tipo alumno. Para ello
bastaría haber hecho:

Programa:

struct alumno {
char nombre[31];
char dirección[21];
unsigned long no_matricula;
unsigned long telefono;
float notas[10];
}alumno1, alumno2;

(123)
Para acceder a los miembros de una estructura se utiliza el operador
punto(.), precedido por el nombre de la estructura y seguido del nombre del
miembro. Por ejemplo, para dar valor al teléfono del alumno alumno1 el valor
943903456, se escribirá:

alumno1.telefono = 943903456;

y para guardar la dirección de este mismo alumno, se escribirá:

strcpy(alumno1.dirección, “C/ Penny Lane 1,2-A”);

La estructura asta ahora esta disponible para dos elementos alumno1 y


alumno2.

El tipo de estructura creado se puede utilizar para definir más variables o


estructuras de tipo alumno, así como vectores de estructuras de este tipo. Por
ejemplo:

struct alumno
{
char nombre[31];
char dirección[21];
unsigned long no_matricula;
unsigned long telefono;
float notas[10];
};

void main()
{
*
*
*
alumno *nuevo_alumno, *clase[300]; //apuntadores a una estructura(2)
// ó
alumno nuevo_alumno,clase[300]; //estructura, vector de estructuras
}

En este caso, nuevo_alumno es una estructura de tipo alumno, y clase[300]


es un vector de estructuras con espacio para almacenar los datos de 300 alumnos. El
número de matrícula del alumno 264 podrá ser accedido como
clase[264].no_matricula (ó clase[264]->no_matricula (2)).

Los miembros de las estructuras pueden ser variables de cualquier tipo,


incluyendo vectores y matrices, e incluso otras estructuras previamente definidas. Las
estructuras se diferencian de los arrays (vectores y matrices) en varios aspectos. Por
una parte, los arrays contienen información múltiple pero homogénea, mientras que
los miembros de las estructuras ser de naturaleza muy diferente. Además, las
estructuras permiten ciertas operaciones globales que no se pueden realizar con
arrays. Por ejemplo, la sentencia siguiente:

clase[298] = nuevo_alumno;

(124)
Hace que se copien todos los miembros de la estructura nuevo_alumno en los
miembros correspondientes de la estructura clase[298]. Estas operaciones globales
no son posibles con arrays.

Se pueden definir también punteros a estructuras:

alumnos *pt;
pt = &nuevo_alumno;

Ahora, el puntero pt apunta a la estructura nuevo_alumno y esto permite una


nueva forma de acceder a sus miembros utilizando el operador flecha(->),
constituido por los signos (-) y (>). Así, para acceder al teléfono del alumno
nuevo_alumno, se puede utilizar cualquiera de las siguientes sentencias:

Pt->telefono;
(*pt).telefono;

donde el paréntesis es necesario por la mayor prioridad de operador (.) respecto a (*).

Las estructuras admiten los mismos modos auto, estern y static que los arrays
y las variables escalares. Las reglas de inicialización a cero por defecto de los modos
extern y static se mantienen. Por lo demás, una estructura puede inicializarse en el
momento de la declaración de modo análogo a como se inicializan los vectores y
matrices. Por ejemplo, una forma de declarar e inicializar a la vez la estructura
alumno_nuevo podría ser la siguiente:

struct alumno {
char nombre[31];
char direccion[21];
unsigned long telefono;
float notas[10];
} alumno_nuevo = {“Mike Smith”, “Sam Martín 87,2º A”, 62419, 421794};

donde, como no se proporciona valor para las notas, estas se inicializan en cero (por
defecto).

Las estructuras constituyen uno de los aspectos más potentes del lenguaje
C++. En esta sección se ha tratado sólo de hacer una breve presentación de sus
posibilidades.

(125)
Gestión dinánica de memoria

Según lo visto hasta ahora, la reserva o asignación de memoria para vectores y


matrices se hace de forma automática con la declaración de dichas variables,
asignando suficiente memoria para resolver el problema de tamaño máximo, dejando
el resto sin usar para problemas más pequeños. Así, si en la función encargada de
realizar un producto de matrices, éstas se dimensionan para un tamaño máximo (100,
100), con dicha función se podrá calcular cualquier producto de un tamaño igual o
inferior, pero aun en el caso de que el producto sea por ejemplo de tamaño (3,3), la
memoria reservada corresponderá al tamaño máximo (100,100). Es muy útil el poder
reservar más o menos memoria en tiempo de ejecución, según el tamaño del caso
concreto que se vaya a resolver. A esto se llama reserva o gestión dinámica de
memoria.
Existe en C++ un operador que reserva la cantidad de memoria deseada en
tiempo de ejecución. Se trata del operador new, del que ya hablamos en los temas
anteriores. Este operador utiliza la siguiente forma:

Sintaxis:

<TDD> *vector; //vector es el nombre de un apuntador


Vector = new <TDD> [variable]; //variable es una variable entera

El operador new se utiliza para para crear variables de cualquier tipo, ya sean
las estándar por el usuario. La mayor ventaja de esta gestión de memoria es que se
puede definir el tamaño del vector por medio de una variable que toma el valor
adecuado en cada ejecución.

Existen también un operador llamado delete que deja libre la memoria


reservada por new y que ya no se va a utilizar. Recordemos que cuando la reserva es
dinámica la variable creada perdura hasta que sea explícitamente borrada por este
operador. La memoria no se libera por defecto en C/C++ a excepción de lenguajes
como Java.

El prototipo de este operador es el siguiente:

delete[] vector;

A continuación se presenta a modo de ejemplo un programa que reserva


memoria de modo dinámico para un vector de caracteres:

(126)
#include <iostream.h>
#include <string.h>
void main()
{
char Nombre[50];
cout <<”Introduzca su nombre:”;
cin >> Nombre;
char *CopiaNombre = new char[strlen(Nombre)+1];
// Se copia el nombre en la variable copianombre
strcpy(CopiaNombre, Nombre);
delete[] CopiaNombre;
}

El siguiente ejemplo reserva memoria dinámicamente para una matriz de


doubles:

#include <iostream.h>
void main()
{
int nfil, ncol, i, j;
double **mat;
//se pide al usuario el tamaño de la matriz
cout << ”Introduzca numero de filas y columnas: ”
cin >> nfil >> ncol;
// se reserva memoria para el vector de punteros
mat = new double*[nfil];
//se reserva memoria para cada fila
for (i=0; i<nfil; i++)
mat[i] = new double[ncol];
//se inicializa toda la matriz
for (i=0; i<nfil; i++)
for (j=0; j<ncol; j++)
mat[i][j]=i+j;
//se imprime la matriz
for (i=0; i<nfil; i++)
{
for (j=0; j<ncol; j++)
cout << mat[i][j]<< “\t”;
cout << “\n”;
}
//se libera la memoria
for (i=0; i<nfil; i++)
{
//se borran las filas de la matriz
delete []mat[i];
//se borra el vector de punteros
delete []mat;
}
}
Constantes de tipo Enumeración

En C++ existe una clase especial de constantes llamadas constantes


enumeración. Estas constantes se utilizan para definir los posibles valores de ciertos
identificadores o variables que sólo deben poder tomar unos pocos valores. Por
ejemplo se puede pensar en una variable llamada dia_de_la_semana que sólo pueda
tomar los 7 valores siguientes: lunes, martes, miércoles, jueves, viernes, sábado
y domingo. Es muy fácil imaginar otros tipos de variables análogas, una de las cuales
podría se una variable booleana con solo dos valores: SI y NO, o TRUE y FALSE, u ON
y OFF. El uso de este tipo de variables hace más claros y legibles los programas, a la
par que disminuye la probabilidad de introducir errores.

En realidad, las constantes enumeración son los posibles valores de ciertas


variables definidas como de ese tipo concreto. Considérese como ejemplo la siguiente
declaración:

enum dia {lunes, martes, miércoles, jueves, viernes, sabado, domingo};

Esta declaración crea un nuevo tipo de variable –el tipo de variable día- que
sólo puede tomar uno de los 7 valores encerrados entre las llaves.

enum dia dia1, dia2;

Y estas variables se les pueden asignar valores de la forma

dia1 = martes;

o aparecer en diversos tipos de expresiones y de sentencias. A cada enumerador se le


asigna un valor entero. Por omisión, estos valores parten de cero con un incremento
unitario. Además, el programador puede controlar la asociación de esos valores como
aparece a continuación,

enum dia {lunes=1, martes, miércoles, jueves, viernes, sabado, domingo};

asocia un valor 1 a lunes, 2 a martes, 3 a miércoles, etc., mientras que la declaración,

enum dia {lunes=1, martes, miércoles, jueves=7, viernes, sabado, domingo};

asocia un valor 1 a lunes, 2 a martes, 3 a miércoles, un 7 a jueves, un 8 a viernes, un


9 a sábado y un 10 a domingo.

Esta asociación no conlleva que las variables tipo enum se comporten como
enteros, son un nuevo tipo de variables que necesitan un cast para que su valor
entero pueda se asignado.

Se puede también hacer la definición de tipo enum y la declaración de las


variables en una única sentencia, en la forma:

enum palo = {oros, copas, espadas, bastos} carta1, carta2, carta3;

donde carta1, carta2, carta3 son variables que sólo pueden tomar los valores oros,
copas, espadas y bastos (equivales respectivamente a 0, 1, 2 y 3).
(128)
Diferencias entre POO y POC

En el lenguaje de computación: POO significa programación orientada a objetos,


mientras que POC se conoce como programación orientada a clases.

Un programa puede implementarse tanto con POO como con POC, la diferencia
radica en que si se programa orientado a objetos cada uno de ellos junto con el
programa controlador o void, aparecen como dispersos y sin relación aparente entre sí,
pueden haber algunas variables comunes varios objetos a los cuales hay que pasársela
por parámetro cada vez que estos son llamados por el main, además de ellos cada
objeto dentro del programa puede llamar a otro cuando desee, esto lo determina el
programador, pero no hay un forma para que el programa por si solo haga estas
divisiones, este tipo de dificultades se corrigen con la POC. Aunque una clase tiene una
mayor jerarquía que un objeto ya que un objeto (acción o función), es una instancia de
una clase.

La librería para generar tiempo en C++ time.h

Implementación:

#include <stdio.h>
//libreria de c++ para prototipos de entrada salida
#include<iostream>
//libreria de c++ para propositos de entrada salida
#include <stdlib.h>
//libreriadec++paraprototiposde conversion de numeros de textos
#include <time.h> //libreria de c++ para prototipos para manipular
fechas y horas
#include <cstring>

//funcion que genera el tiempo


int generar_tiempo()
{
//comienza la accion tiempo retorna un entero
int valor=0; //entero con valor cero
srand( (unsigned)time( NULL ) );
/*hace la comparacion con respecto al reloj de la computadora*/
valor= (1 + rand() % 10 ) ; //saca un numero entero entre 1 y 10
return valor; //retornamos el valor de el tiempo en la variable valor
}//final de la funcion generar tiempo objeto

Uso del: system(“cls”)

Sirve para limpiar la consola de la interfaz usuario de cpp en automático.

(129)
Creación de un objeto en C++

//Esta es la forma como se declara su prototipo:

void detalle (int tabulacion,int espacio,int sensor,int bandera);


void detalle (int,int,int,int); //una forma especial de prototipo

void detalle (int tabulacion,int espacio,int sensor,int bandera)


{
//adornos del objeto
char caracter[16]=
{'-','*','=','>',':','@','_','<','.','+','x','#','?','M','|','X'};
char mansu[8]={' ','(','[','{',' ',')',']','}'};
char menu[7]={'W','O','8','/','9','6','o'};

//variables locales a detalle

int global,global2,global3,global4;
global=global2=global3=global4=0; //validación de todas en una línea
if((tabulacion<0)|(espacio<0)|(sensor<0)|(bandera<0))
{
detalle(1,1,0,666); //llamada recursiva
}
if(bandera==0)
{
if((tabulacion==0)&(espacio==0))
{} //hall
else if((tabulacion==0)&(espacio!=0))
{
for(global4=1;global4<=espacio;global4++){printf(" ");}
}
else
{
for(global4=1;global4<=tabulacion;global4++){printf("\n");}
if(sensor!=0){detalle(0,espacio,0,bandera);}
}
}//fin de bandera=0
if((bandera<200)&((bandera==1)|(bandera>=2))|
((tabulacion==0)&(espacio==0)&(sensor!=0)))
{
if((sensor==0)&(espacio==0))
{
if((tabulacion>-1)&(tabulacion<25))
{
global3=79;
if((bandera>2)&(bandera<80))
{
global3=global3+bandera*(-1)+2;
}
if((bandera>=80)&(bandera<156))
{
global2=1;
if(bandera!=155)
{
global4=1;
}
if((bandera>80)&(bandera<155))
{
global3=global3+bandera*(-1)+80;
}
}
if(bandera>155)
{detalle(1,2,0,666);}
while(global<global3)
{
if((global2==0)&(global4>=0))
{
if((tabulacion>(-1))&(tabulacion<6))
{
printf("%c",menu[tabulacion]); //W
}
else
{
if(tabulacion<22)
{
if(espacio==0)
{
sensor=tabulacion;
sensor=sensor-6;
espacio++;
}
printf("%c",caracter[sensor]); //W
}
else if(tabulacion==23)
{
if(global!=0)
{
if(global%2==0)
{
printf("%c",menu[4]); //O
}
else if((global%2!=0)|(bandera==2))
{
printf("%c",menu[5]);
}
}
else
{
printf("%c",mansu[0]); //O
}
}
else
{
if(global%2==0) //case 24
{
printf("%c",caracter[5]);
}
else if((global%2!=0)|(bandera==2))
{
printf("%c",menu[3]); //O
}
}
}
if(bandera==2)
{
global=78;
}
if(global4==1)
{
global2=1;
}
}
else
{
detalle(0,1,1,0);
global2=0;
}
global++;
}
}
else
{detalle(1,0,0,666);}
}
else
{
if((tabulacion==0)&(espacio==0)&(sensor!=0))
{
espacio=sensor;
tabulacion=bandera;
bandera=-1;
}
else
{
if(espacio>70)
{
sensor=espacio-71;
//se cambio por detalle(2,sensor,1,0);
//en automatico se puede copiar y pegar a gusto
}
detalle(bandera,sensor,1,0); //en automatico se puede copiar y pegar a gusto
//se cambio por detalle(bandera+1,sensor,1,0);
}
if((espacio<4)&(espacio>-1))
{
printf("%c%d%c",mansu[espacio],tabulacion,mansu[espacio+4]);
}
else if(espacio==4)
{
printf("%d",tabulacion);
}
else if((espacio>4)&(espacio<26))
{
global=espacio-5;
detalle(global,0,0,2);
}
else if((espacio>25)&(espacio<34))
{
global=espacio-26;
printf("%d%c",tabulacion,mansu[global]);
}
else if((espacio>33)&(espacio<50))
{
global=espacio-34;
printf("%d%c",tabulacion,caracter[global]);}
else if(espacio==50)
{printf("%c%c",caracter[0],caracter[8]); // -.
}
else if(espacio==51)
{
printf("%c%c",caracter[2],caracter[3]); // =>
}
else if(espacio==52)
{
printf("%c%c",caracter[3],caracter[0]); // >-
}
else if(espacio==53)
{
printf("%c%c",caracter[7],caracter[3]); // <>
}
else if(espacio==54)
{
printf("%c%c",caracter[0],caracter[3]); // ->
}
else if(espacio==55)
{
printf("%c%c%c",caracter[7],caracter[0],caracter[3]); // <->
}
else if((espacio>55)&(espacio<59))
{
global=1;
if(espacio==56)
{
printf("%c%c",mansu[global],mansu[global+4]); // ()
}
if(espacio>56)
{
global++;
if(espacio==57)
{
printf("%c%c",mansu[global],mansu[global+4]); // []
}
if(espacio>57)
{
global++;
printf("%c%c",mansu[global],mansu[global+4]); // {}
}}}
else if(espacio==59)
{
printf("%c%c",caracter[1],caracter[0]); // *-
}
else if(espacio==60)
{
printf("%c%c",menu[1],caracter[0]); // O-
}
else if(espacio==61)
{
printf("%c%c%c",mansu[2],caracter[15],mansu[6]); // [X]
}
else if(espacio==62)
{
printf("%c%c",mansu[6],caracter[0]); // ]-
}
else if(espacio==63)
{
printf("%c%c",menu[6],caracter[0]); // o-
}
else if(espacio==64)
{
printf("%c%c%c%c%c",caracter[6],menu[6],menu[1],menu[6],caracter[6]); //_oOo_
}
else if(espacio==65)
{
printf("%c%d%c",caracter[14],tabulacion,caracter[14]); // o|o
}
else if(espacio==66)
{
printf("%c%c%d%c%c",caracter[6],menu[6],tabulacion,menu[6],caracter[6]); // _o*o_
}
else if(espacio==67)
{
printf("%c%c%d%c%c",caracter[0],mansu[2],tabulacion,mansu[6],caracter[0]);
}
else if(espacio==68)
{
printf("%c%c%d%c%c",caracter[0],mansu[3],tabulacion,mansu[7],caracter[0]);
}
else if(espacio==69)
{
printf("%c%c%d%c%c",caracter[0],mansu[1],tabulacion,mansu[5],caracter[0]);
}
else if(espacio==70)
{
printf("%c%c%c%d%c%c%c",caracter[6],menu[6],caracter[14],tabulacion,caracter[14],
menu[6],caracter[6]); }
if((bandera==(-1)))
{}
else
{
if(espacio<71)
{
detalle(0,1,0,0); //es en automatico
//se cambio por detalle(0,bandera,0,0);
}
else
{
if(sensor!=0)
{
sensor/=2;
if(sensor%2!=0)
{
sensor=sensor-1;
}
detalle(0,sensor,0,0); //no es automatico
}}}}}
if(bandera==666)
{

//tutorial y capciones del objeto

if((sensor==666)&(espacio==666)&(tabulacion==666))
{
printf("\n\n TUTORIAL: detalle(x,c,v,z); Version Premiun\n\n");
printf("(x,0,0,0) baja un x numero de lineas en blanco(1)
\n si x=300...aprox limpia pantalla por arriva\n");
printf("(0,c,0,0) escribe un caracter vacio un c numero de\n veces(2)\n");
printf("(x,c,1,0) hace (1) y (2) al mismo tiempo\n");
printf("(x,0,0,1) separa segun el valor de x que se ponga x=[0...]\n");
printf("(x,0,0,2) imprime un solo caracter x=[0...]\n");
printf("(x,c,v,z) x numero de opcion 1,c caracter [1], v espaciado(1) 1x1 _[1],\n
z espaciado(2) [1]_\n");
printf(" x=[1,..], c=[1,..], v=[0,..], z=[1,..]\n");
printf("(0,0,v,z) (4)imprime caracteres v especiales,\n y la opcion z si tienen
numeracion\n");
printf("(0,0,v,0) imprime tambien caracteres v especiales como (4),\n sin
numeracion z=0\n");
printf("(x,0,0,81>z>2) separa recortando la linea escojida\n segun el valor de
z\n");
printf("(x,0,0,z=80) coloca una linea semirecortada\n");
printf("(x,0,0,155>z>80) recorta la linea semirecortada segun x\n");
printf("(x,0,0,155) centra la linea de separacion x\n");
printf("(0,0,0,0) accion estable no pasa nada...\n");
printf("\n\n SOLO: USO de accion en CORRERMENU(c,y1,y2,...,i) =>
detalle(x,c,v,z)\n");
printf(" paramero recomendado para z es 2 por defecto\n");
printf("\n\n c=70 MAX signos (variable caracter) hace (1) y (2)\n\n
automatic...OK!\n");
printf("\n\n CODIGO HECHO POR <-/DZ/-> trabaja por mi!\n");
}
else
{
if(tabulacion==1)
{
printf("\n\n Mal uso de detalle(x,x,x,x)");
if(espacio==0)
{
printf("\n\n Parametro fuera de alcanze de arreglos\n\n 25-30 caracteres
MAX...\n");
}
if(espacio==1)
{
printf("\n\n La funcion no asepta parametros negativos\n");
}
if(espacio==2)
{
printf("\n\n ha pasado al menos un parametro mal bandera debe ser < 155\n");
}}}}}

//fin del objeto

Las aplicaciones de este objeto son varias aunque solo se use para la añadir adornos a
los menús, cópielo en un archivo cpp y guárdelo con la extensión .hpp para llamarlo a
otro archivo .cpp cuando quiera.

(135)
Plantilla de menú en C++ (una forma muy básica)
#include <stdlib.h> /*librerías estándar de C*/
#include <stdio.h> /*librerías estándar de C*/
#include <iostream.h> /*uso del cin y cout por a veces puede arrojar warning*/
#include <time.h>
#include <conio.h>
#include <string.h>
#include “detalle.hpp” //se agrega un archivo de cabecera que es precisamente
//el objeto que se creo anterior mente
int escribir(int,int); // prototipo de función “simplificado” equivale a
// int escribir(int menu,int liga)
int main()
{
int client,taqui,titu;
char indi;
indi='?';
client=taqui=titu=0;
/* B L O Q U E D E L P R O G R A M A */
escribir(0,0); //escritura
detalle(1,0,1,0); //tabulacion
detalle(2,0,0,1); //separa
detalle(1,4,1,0); //tabulacion
escribir(0,1); //escritura
detalle(1,0,0,0); //tabulacion
detalle(2,0,0,1); //separa
detalle(1,0,1,0); //tabulacion
escribir(0,2); //escritura
escribir(0,3); //escritura
scanf("%s",&indi); //lectura de la variable menu
detalle(0,0,0,1); //separa
switch(indi)
{
//hay solo 3 casos
case '1':
detalle(300,0,0,0); //limpia la pantaya
detalle(1,4,1,0); //tabula
escribir(1,0); //escritura
detalle(1,4,1,0); //tabula
escribir(1,2); //escritura
detalle(1,4,1,0); //tabula
escribir(1,3); //escritura
detalle(2,0,0,0); //limpia la pantaya
goto reynapepiada; //se hace un salto de linea
break;
case '2':
detalle(300,0,0,0); //limpia la pantaya
escribir(2,0); //escritura
detalle(2,0,0,0); //asi se separa
goto reynapepiada; //se hace un salto de linea
break;
default: //caso 3 o o una letra!!!
if(indi=='3')
{

/*F I N B L O Q U E D E L P R O G R A M A */

panconqueso: //etiqueta 1
detalle(1,4,1,0); //tabula
escribir(3,0); //escritura
}
else
{
detalle(300,0,0,0); //limpia la pantaya
detalle(0,4,1,0); //tabula
if((indi=='4')|(indi=='5')|(indi=='6')|(indi=='7')|(indi=='8')|(indi=='9')|
(indi=='0'))
{
escribir(3,1); //escritura
}
else
{
escribir(3,2); //escritura
}
reynapepiada: //etiqueta 2
detalle(0,0,0,1); //separa
escribir(2,1); //escritura
escribir(0,3); //escritura
scanf("%s",&indi); //lectura de la variable menú
detalle(0,0,0,1); //separa
if(indi=='1')
{
detalle(300,0,0,0); //limpia la pantaya
main(); //se hace la bendita llamada al main
}
else
{
goto panconqueso; //se hace un salto de línea
}}
break;
}
return 0;
}
/*A CONTINUACION SE DESCRIBE LA FUNCION ESCRIBIR*/

int escribir(int menu,int liga)


{
if(menu==0)
{
if(liga==0)
{printf("\n Universidad Central de Venezuela
\n Facultad de Ciencias\n Escuela de Computacion\n");}
else if(liga==1)
{printf("\n EL BANCO ESTA ABIERTO...
\n\n SIMULACION DE UNA COLA EN UN BANCO\n");}
else if(liga==2)
{printf(" Menu de opciones:
\n\n 1) Comenzar simulación
\n\n 2) Desarrolladores
\n\n 3) Salir");}
else
{printf("\n\n Escoja una opcion: ");}
}
else if(menu==1)
{
if(liga==0)
{printf("CARGANDO DATOS PARA LA SIMULACION...OK\n");}
else if(liga==1)
{printf("GENERANDO SISTEMA DE COLAS UNIFORME...OK\n");}
else if(liga==2)
{printf("REGISTRANDO LAS OPERACIONES DEL DIA...OK\n");}
else
{printf("ADMINISTRADO LA ATENCION AL CLIENTE...OK\n");}
}
else if(menu==2)
{
if(liga==0)
{printf("\n Hecho por:\n\n Daniel Zenobio CI 17141735");}
else
{printf("\n Precione (1) para volver al menu principal
\n precione otra tecla para salir. ");}
}
else
{
if(liga==0){printf("Gracias por usar nuestro programa...!!!\n\n");}
if(liga==1){printf("ERROR!!! OPCION U PARAMETRO INVALIDO\n");}
if(liga==2){printf("ERROR!!! NO PUEDE ESCRIBIR LETRAS SOLO NUMEROS\n");}
}
return 0;
}

(138)
Recursividad en C++

Le lenguaje C soporta recursividad, un programa u objeto que se comporta de


manera recursiva, es aquel que se invoca a si mismo un numero finito de veces, para
encontrar una solucion, basaría ver el código del objeto detalle del cual se hablo
anteriormente, el cual usa mucha recursividad.

La función factorial puede representarse de manera recursiva de manera:

int factorial(int aux)


{
if(aux==0)
{
return(1);
}
else
{
return(aux*factorial(aux-1));
}
}
No obstante la recursividad suele crear problemas cuando se le pasan parámetros
muy altos, además de ello cada vez que un programa se invoca a si mismo este apila
una cantidad de datos que usara en el siguiente nivel recursivo lo que indica una gasto
en memoria, en ciertos problemas los programas que resuelven recursivamente un
problema especifico encuentran su solución en un nivel recursivo, sin embargo estos
continúan llamándose recursivamente por lo que el valor se “pierde” en el siguiente
nivel recursivo en tales casos es conveniente el uso de “hoyos”, es decir que cuando se
encuentre la solución se haga una llamada al objeto pero que esta caiga en un lugar
vacío, ejemplo con factorial:

Supongamos se la llamada se efectúa en el main() de la forma:

factorial(5,0);

int factorial(int aux,int indicador)


{
If(indicador==0)
{
if(aux==0)
{
return(1);
}
else
{
if (aux<=3)
{} //no hace nada
else
{return(aux*factorial(aux-1,indicador));}
}
}

(139)
Los ciclos infinitos de C++ (uso de palabras break y continue)

Una forma de hacerlos es la siguiente:

while(1){} //desde luego estas no son formas normales

do{}while(1); Ciclo condicional, puede


ejecutarse o no.
Progresivos
El contador Ciclo incondicional, se ejecuta
aumenta siempre
Ciclos(bucles)

El contador es independiente, si su
Regresivos límite de incremento o decremento
El contador depende de una constante
disminuye
El contador dependiente el límite
de incremento o decremento lo
puede modificar el usuario
Instrucciones de salto de línea
El número del contador indica
Palabra reservada continue: un caso o situación especial
como es el caso especial del FOR

opcion=0;n=4;
while (opcion<n) //el contador aumenta dependiendo del valor de n
{
printf(" YO ENTRO SIEMPRE ");
opcion++;
if(opcion==2)continue; //se es verdadero la siguentes lineas no se ejecuta
//sino que se inicia el siguiente ciclo
printf("->CON PERMISO");
}

Corrida en frío:

opción Cadena1 Cadena2


0 “YO ENTRO SIEMPRE”
1 “YO ENTRO SIEMPRE” "CON PERMISO"
2 “YO ENTRO SIEMPRE” (se salta la línea)
3 “YO ENTRO SIEMPRE” "CON PERMISO"
4=n "CON PERMISO"

Tanto el while() como el do-while() son como funciones que reciben datos
booleanos 0 es falso y distinto de cero es verdad.

(140)
Es decir genera la secuencia:

YO ENTRO SIEMPRE->CON PERMISO YO ENTRO SIEMPRE


YO ENTRO SIEMPRE->CON PERMISO YO ENTRO SIEMPRE->CON PERMISO

Existen otras formas de usar las sentencias con continue otra forma es:

opcion=0;n=4;

while (opcion<n)
{
printf(" YO ENTRO SIEMPRE ");
opcion++;
if(opcion==2)
{
printf("->SIN PERMISO");
continue; //salto de línea
} //sino que se inicia el siguiente ciclo
printf("->CON PERMISO");
}

Corrida en frío:

opción Cadena1 Cadena2


0 “YO ENTRO SIEMPRE”
1 “YO ENTRO SIEMPRE” "CON PERMISO"
2 “YO ENTRO SIEMPRE” "SIN PERMISO"
3 “YO ENTRO SIEMPRE” "CON PERMISO"
4=n "CON PERMISO"

opcion=0; n=4;

while(opcion<n)
{
printf(" YO ENTRO SIEMPRE ");
opcion++;
if(opcion==2)
{
printf("->SIN PERMISO");
/*si entra aquí ya salio del condicional incluido del sino por lo que pasa a la línea
después del continue*/
}
else
continue; //es equivalente a else{continue};
printf("->CON PERMISO");
}

(141)
Corrida en frío:

opción Cadena1 comparación Cadena2


0 “YO ENTRO SIEMPRE”
1 “YO ENTRO SIEMPRE” 1==2(false) (se salta la linea)
2 “YO ENTRO SIEMPRE” "SIN PERMISO" "CON PERMISO"
3 “YO ENTRO SIEMPRE” 3==2(false) (se salta la línea)
4=n 4==2(false) (se salta la línea)

Sin embargo considere el siguiente conjunto de instrucciones:

while (opcion<4)
{

printf("YO ESRIBO SIEMPRE");

if(opcion==2)continue;

/*si opción=2 las líneas siguientes no se leerán por el programa ya que se iniciara
el siguiente ciclo*/

printf("YO ESRIBO");
opcion++; // ERROR!!!
}

Este conduce a un ciclo infinito ya que la sentencia continue esta antes del incremento
por lo que cuando opcion=2 es erróneo.

Corrida en frío:

opción Cadena1 comparación Cadena2


0 “YO ENTRO SIEMPRE” 0==2(false) “YO ESCRIBO”
1 “YO ENTRO SIEMPRE” 1==2(false) “YO ESCRIBO”
2 “YO ENTRO SIEMPRE” 2==2(true) (se salta la línea)
2 “YO ENTRO SIEMPRE” 2==2(true) (se salta la línea)
2 “YO ENTRO SIEMPRE” 2==2(true) (se salta la línea)
(2==4)? … … …

Este error ocurre porque se esta saltando el incremento por lo que en ciclos la
sentencia continue debe colocarse después del incremento.

Veamos ahora un ciclo incondicional, con contador, usando la sentencia break.

(142)
n=0;

while(1)
{
opcion++;

/*
.
conjunto de intrucciones que se ejecutaran n veces
.
.
*/

if(opcion==n)break;
}

Otra forma de programar con break.

opcion=0;

while(1)
{
opcion++;

printf(" YO ENTRO SIEMPRE ");

if(opcion==2)
{
printf("->SIN PERMISO");
break;
}else{
printf("->CON PERMISO");
}
}

Estas instrucciones generan la secuencia:

“YO ENTRO SIEMPRE ->CON PERMISO YO ENTRO SIEMPRE ->SIN PERMISO "

opción Cadena1 comparación Cadena2


0 “YO ENTRO SIEMPRE”
1 “YO ENTRO SIEMPRE” 1==2(false) "CON PERMISO"*
2 2==2(true) "SIN PERMISO"

*Hay un salto de línea en la línea que sigue a esta por el break.


(143)
Otra forma quizás más formal de escribir un ciclo es:

opcion=n;

while(1)
{
/*
.
conjunto de instrucciones que se ejecutaran n+1 veces
.
.
*/
if(opcion<n){opcion++;}else break;
}
Instrucciones inmediatas:

Son de la forma por ejemplo

opcion=0;

if(opcion!=0)
printf(“prueba 1”); ß Este es el cuerpo de alcance del if, no se ejecuta
printf(“prueba 2”); ß Se ejecuta ya que esta fuera del alcance
printf(“prueba 3”); ß se sigue ejecutando…

En otros casos:

for(opcion=0;opcion<4;opcion++)
printf("prueba"); ß cuerpo del for implicito se escribe 4 veces
printf(“prueba 2”); ß fuera del cuerpo del for se escribe una vez

Una instrucción inmediata es el cuerpo implícito restringido a una línea que se


ubica justo después de una sentencia con alguna palabra reservada. En donde se ubica
una sola instrucción.

Con bucles como while y do while no es aconsejable el uso de instrucciones


inmediatas.

(144)
Paso de punteros y variables a objetos

Pase por valor


También llamado paso por copia, significa que cuando C++ compila
la función y el código que llama a la función, la función recibe una copia de los valores
de los parámetros. Si se cambia el valor de un parámetro, variable local, el cambio
solo afecta a la función, la función solo recibe una copia de los valores de los
parámetros.

Paso de punteros por referencia


Cuando una función debe modificar el valor de parámetro pasado y
devolver este parámetro pasado a la función llamadora se ha utilizado el método de
paso parámetro por referencia o dirección.

Ejemplo:
func_i(int i)
main() {
{ i++;
int i=6; return; //es igual a return 0;
func_i(i); }
return;
}

El método por defecto de pasar parámetros por valor es por valor, a menos que se
pasen arrays, ya que los arrays se pasan siempre por dirección.

(145)
struct persona
{
int ID;
persona *prox;
};

main()
{
int A ,*B,*C,*D; //se declara una variable y tres apuntadores a entero
A=7; //A puede no inicializarse
char *name[10]; //arreglo de apuntadores
char aname[3][4]; //es un arreglo de 2D de 200 elementos.
<TDD> E[n]={g0,g1,g2,g3,….,g(n-1)}; //un arreglo cualquiera n>-1

persona *tipo;
tipo=new persona;
tipo->prox=NULL;
tipo->ID=0;

B=&A; //B es un alias de A y contiene la dirección de memoria donde esta A


*B=10; //A y *B ahora valen 10,
// B=10? las posiciones de memoria no pueden modificarse
C=&(*B); //C contiene la dirección de memoria donde esta el apuntador B
D=&(*C); //D contiene la dirección de memoria donde esta el apuntador C
*D = 100; //*D,*B,*C,A ahora valen 100
A=func_1(A); int func_1(int A){A++;return A;}
Funcion2(A);
Funcion3(&B,&C,&D);
Funcion4(B,C,D);
Funcion5(*B,*C,*D);
Funcion6(E); /*se esta pasando la primera posición de memoria del arreglo E
Equivale a: Funcion6(&E[0]); */
Funcion7(tipo); //se pasa un apuntador a al primer nodo por valor
Funcion8(&tipo); // se pasa un apuntador a al primer nodo por referencia

return 0;
}

Sobre el arreglo name:

name tiene 10 elementos que son apuntadores no inicializados. La ventaja es que los
vectores de cada fila pueden ser de longitudes diferentes name[3][4] y aname[3][4].
Son correctas en C.

(146)
int func_1(int A){}

En este caso el valor de A si se modifica al tomar el valor que devuebe fun_1. ya que
se modifican la posiciones de memoria con el operador return. En el hall*.

*Entiéndase por hall un bloque de la forma {}

int Funcion2(int &A){}

En este caso gracias al operador de dereferenciación el valor de A se modifica dentro y


después de llamarse la función. Ya que se pasa por referencia.

int Funcion3(int **B,int **C,int **D){**B++;}

En este caso se pasan apuntadores por referencia, el trabajo que se puede hacer
dentro de hall la variable debe tener el mismo tamaño del asterisco debe ser el mismo
al tamaño de los asteriscos especificado en los parámetros.

int Funcion4(int *B,int *C,int *D){*B=10;}

Los apuntadores se pasan por referencia.

int Funcion5(int B,int C,int D){B=10;}

Los apuntadores se pasan por valor.

int Funcion6(int E[n]){B[0]=10;} //otra forma es Funcion6(int *E){B[0]=10;}

Los arrays sempre se pasan por referencia ya que lo que realmente se pasa es la
direccion de memoria del primero elemento del arreglo.

Cuando se trabajan con registros y punteros la otra forma es:

int Funcion7(struct persona *tipo)


{tipo=new <Nregistro>; tipo-><campo>=<valor>;}

De esta forma el puntero tipo se pasa por valor.

int Funcion8(struct persona **tipo)


{*tipo=new <Nregistro>;(*tipo)-><campo>=<valor>;}

De esta forma el puntero tipo se pasa por referencia.

En los struct los apuntadores por lo general se suelen pasar por referencia siempre,
un apuntador cuando se declara no tiene valor especifico, solo tiene una dirección de
memoria donde se encuentra un dato en especifico. Si no apunta a ningún valor
almacenado en alguna variable, el apuntador por lo general apunta a null.

(147)
Línea de comandos:

El siguiente código le indicara la dirección en donde se encuentra su programa:

main(int argc,char **argv)


{
int i;
printf("argc= %d\n",argc);
/*programa que imprime los argumentos de la línea de comandos*/
for(i=0;i<argum;++i)
{
printf("argc[%d]: %s\n",i,argv[i]);
}
scanf("%d",&i);
}

Entrada / Salida

*Archivos
La primera operación sobre un archivo antes de usarlo es abrirlo:

FILE *fopen(char *name,char *mode)

Los modos de apertura incluyen:


“r” àlectura
“w”àescritura
“a”àinsertar al final “append”.

*Para abrir un archivo se debe declarar un (file pointer) que apunta a un escritura del
tipo FILE.

FILE *stream, *fopen();


if((stream=fopen(“myfile.dat”,”r”))==NULL)
{
printf(“No se pudo abrir el archivo %s\n”,”myfile.dat”);
exit(1); //finaliza la ejecución del programa en algunos compiladores,
}

(148)
Variables vs Apuntadores

*C es un apuntador de enteros, contiene solo un espacio en memoria no apunta a


nada, NULL por defecto

A es una variable, contiene una dirección en memoria y un valor asignado. Si se le


coloca el & entonces A se convierte en una apuntador que devuelve la dirección de la
variable.

Nota: *C y A ambos son variables. Mientras que C y &A, ambos indican una posición
de memoria especifica de memoria.

A=*(&A); mientras igual para C=*(&C)=&A;

El uso del operador & es generalmente para variables mientras que el * es para
apuntadores.

Objeto vs Clase

“Si se programa usando una clase implica a la vez que se programa también mediante
el uso de objetos, cuando se programa orientado a objetos lo contrario no es cierto”

“Un objeto se dice que es operativo, una clase no”

“Una clase constituye un ámbito “implícito” donde se relacionan o no variables y


objetos, mientras que en la programación orientada a objeto este ámbito pareciera no
existir ya que los objetos se relacionan de manera explicita, los pase de variables
llamadas a objetos, variables globales locales, todo lo establece explícitamente el
programador”

“Si un objeto siempre va a ser una instancia lo que lo hace independiente de la clase,
pero si pertenece a una clase se dice que es un método de una clase, una clase
necesita poseer métodos”

“Los objetos son las instancias básicas a usar en caso de resolver problemas básicos
como la función factorial”

“Las clases son usadas mas para problemas mas complejos donde el numero de
objetos es numeroso al igual que las variables y se necesita de alguna manera un
ámbito que ordene estos métodos, los relacione, establezca una jerarquía, separe, etc.
por el programador, por ejemplo un problema que abarque el uso de mas de 20
objetos”

“Cuando se programa orientado a objetos todos los objetos a excepción de main tienen
la misma jerarquía”

“Hasta ahora no se conoce si un problema puede resolverse mediante clases o objetos”

“La programación orientada a objetos corresponde perfectamente con el método


divide y vencerás, desde un enfoque mas básico que si se usa una clase que los
engloba y los relaciona de manera implícita”

(149)
“Un struct es un objeto supongamos no usamos clase, este es una “plantilla” pero si
manejamos el struct como si fuera una clase y es valido! este seria además un ámbito
en donde están unas variables u objetos es decir una clase es una plantilla también
pero de objetos y/o variables* el cual es el concepto que se le da en los primeros
semestres”.

“La programación usando clases es de alguna forma mas elegante que la programación
orientada a objetos, ya que si se tiene un gran numero de estos probablemente estos
estén relacionados pero dispersos lo que les da un aspecto de desordenados”

B. define una clase como “un conjunto de objetos que comparten una estrutura
(ámbito) y comportamiento comunes”.

“Una clase no abarca espacio en memoria. El almacenamiento se asigna cuando se


crea un objeto de una clase”

“Una variable puede ser un objeto, lo contrario no es cierto”

*variables que en los primero semestres se les denominan campos tales como el
nombre, apellido, cedula, edad, cargo, etc. que pueden ser manipulados dentro de la
clase como si esta fuera un registro

Aprendiendo a programar con Clases:

Definición de una clase:

Antes que un programa pueda crear objetos de cualquier clase, esta debe ser definida.
La definición de una clase significa que se debe dar a la misma un nombre, darle
nombre a los elementos que almacenan sus datos y describir las funciones que
realizaran las acciones consideradas en los objetos.

Las definiciones o especificaciones no son códigos de programa ejecutable. Se utilizan


para asignar almacenamiento a los valores de los atributos usados por el programa y
reconocer las funciones que utilizará el programa, normalmente se sitúan en archivos
diferentes de los archivos de códigos ejecutables, utilizando un archivo para cada
clase. Se conocen como “archivos de cabecera” que se almacenan con un nombre de
archivo con extensión, luego llame a la clase en el main() con la instrucción:
#include “extension.hpp”

(Para mas información consulte las paj. (48) de este manual)

Formato:

class nombre_clase
{
<campos1…n>; //variables por lo general
.
<objetos1…n>; //acciones, funciones, datos miembros de la clase
.
};

(150)
Ejemplo:

class punto
{
public:
int leerx(); //prototipo de una función
void fijarx(int); // “ “ “ acción
private:
int x; //variables
int y;
};

Otra forma es:

class edad
{
private:
int edadhijo,edadmadre,edadpadre; //datos
public;
edad();
void iniciar (int,int,int); //functiones miembro de la clase
int leerhijo();
int leermadre();
int leerpadre();
}

Prototipo de clases:

Una declaración de una clase consta de una palabra reservada class y el nombre
de la clase. Una declaración de la clase se utiliza cuando el compilador necesita
conocer una determinada clase definida totalmente en alguna parte del programa. Por
ejemplo:

class punto; //definida en algún lugar

Objetos de clases:

Una vez que la clase ha sido definida, un programa puede contener una instancia de
una clase, denominado un objeto de una clase.

Formato: nombre_clase identificador;

Así la definición del objeto punto es:

Punto p;

(151)
El operador acceso a un miembro (.) selecciona un miembro individual de un objeto de
la clase. Las siguientes sentencias por ejemplo, crean un punto P, que fija su
coordenada x y la visualiza a continuación.

Punto p;
p.fijarx(100);
cout<<” coordenada x es “<<p.leer();

El operador punto se utiliza con los nombres de las funciones miembro para especificar
que son miembros de un objeto.

Ejemplo:
class DiaSemana; //contiene la función visualizar
DiaSemana Hoy; //Hoy es un objeto
Hoy.visualizar(); //ejecuta la función visualizar

Se puede asignar un objeto de una clase a otro; por defecto, C++realiza una copia bit
a bit de todos los miembros dato. En otras palabras, todos los miembros físicamente
contenidos en el área de datos del objeto fuente se copian en el objeto receptor. Por
ejemplo, el siguiente código crea un punto llamado P2 y lo inicializa con el contenido
de P.

Punto P;
//. . .
Punto P2;
P2=P;

Un principio fundamental en programación orientada a objetos es la ocultación de


información que significa que a determinados datos del interior de una clase no se
puede acceder por funciones externas de la clase. El mecanismo principal para ocultar
datos es ponerlos en una clase y hacerlos privados. A los datos o funciones privados
solo se puede acceder desde dentro de la clase. Por el contrario las funciones públicas
son asequibles desde el exterior de la clase.

CLASE
No asequibles
desde el exterior Privado
de la clase
(acceso denegado) Datos o funciones

Asequible desde Publico


el exterior de la Datos o funciones
clase

Secciones públicas y privadas de la clase.

(152)
Se utilizan tres diferentes especificadotes de acceso para controlar el acceso a los
miembros de la clase estos son: public, private, protected. Se utiliza el siguiente
formato general en definiciones de la clase situando primero las funciones miembro
publicas, seguidas por los miembros protegido y privado (este orden sin embargo no
es obligatorio).

Formato:

class nombre_clase
{
public:
//elementos públicos
protected:
//elementos protegidos
private:
//elementos privados
};

El especificados public define miembros públicos, que son aquellos a los que se puede
acceder por cualquier función. A los miembros que siguen el especificador private solo
se puede acceder por funciones miembro a la clase o por funciones y clases
amigas. A los miembros que siguen el especificador protected se puede acceder por
funciones miembros de la clase o clases derivadas de la misma(Subclase), así como
por amigas. Los especificadotes public, private y protected pueden aparecer en
cualquier orden.

Tipo de miembro M. de la clase Clase amiga M. una Subclase F. no miembro


private X X
protected X X X
public X X X X

Si se omite el especificador de acceso, el acceso por defecto es privado, en la siguiente


clase Estudiante, por ejemplo todos los datos son privados, mientras que las funciones
miembro son publicas.

class estudiante
{
long numid;
char nombre[40];
int edad;
public:
long leerNumid();
char *Leernombre();
int leeredad();
};

1- Siempre se pone la sección privada de primero, debido a que contiene los


atributos datos.
2- Poner la sección publica de segundo debido a que las funciones miembros y los
constructores son la interfaz del usuario de la clase.

(153)
Funciones miembro:

Las funciones miembro son funciones que se incluyen dentro de una clase, estos son
llamados también métodos de la clase.

class producto
{
private:
int numerodeproducto;
char nombredelproducto[30];
descrip_producto[80];
float precio_producto, num_unidades;

public:
producto(int, char[],char[],float,float);
void verproducto();
float obtenerpresio();
void actualizarproducto(int)
};

La clase Punto define las coordenadas de un punto en un plano. Por cada dato se
proporciona una función miembro que devuelve su valor y una que fija su valor.

class Punto
{
Public:
int leerX(){return x;}
int leery(){return y;}
void FijarX (int valx){x=valx;}
void FijarY (int valy){y=valy;}
private:
int x;
int y;
};

Las funciones miembro de una clase se definen de igual modo que cualquier otra
función, excepto que se necesita incluir el operador de resolucion de ámbito (o
conocido como operador de alcance unario). :: en la definición de la función (en su
cabecera).

Formato:

<TDD> <nomb_clase>::<nomb_funcion>(<lista de parametro>) {}

Las declaraciones de las funciones en este ejemplo son también definiciones ya que se
ha incluido el cuerpo de cada función. Si un cuerpo de la función consta de una única
sentencia, muchos programadores sitúan el cuerpo de la función en la misma línea en
el nombre de la función. Por otra parte, si una función contiene múltiples sentencias,
cada una debe ir en una línea independiente. Por ejemplo:

(154)
class Punto
{
public:
void fijarX(int valx)
{
if((valx>=-100)&&(valx<=100))
x=valx;
else
cerr<<”Error: Fijarx() argumento fuera de rango”;
}
// . . .
};

Tipos de funciones miembro

Las funciones miembro que pueden aparecer en la definición de una clase se clasifican
en función de tipo de operación que representan.

*Constructores y destructores, son funciones miembro a las que se llama


automáticamente cuando un objeto se crea o se destruye.

*Selectores que devuelven los valores de los miembros dato.

*Modificadores o mutadores que permiten a un programa cliente cambiar los


contenidos de los miembros dato.

*Operadores que permiten definir operadores estándar C++ para los objetos de las
clases.

*Iteradotes que procesan colecciones de objetos, tales como arrays y listas.

Funciones en línea y fuera de línea

Hasta ese momento, todas las funciones se han definido dentro del cuerpo de la
definición de clase. Se denominan definiciones de función en línea (inline). Para el
caso de funciones más grandes, es preferible codificar solo el prototipo de la función
dentro del bloque de la clase y codificar la implementación de la función en el exterior.
Esta forma permite al creador de la clase ocultar la información de la función al usuario
de la clase proporcionando solo el código fuente del archivo de cabecera, junto con un
archivo de implementación de la clase precompilada.

class punto Programador, creador de la clase


{ (conjunto de Implementaciones)
public:
void fijarx(int valx);
Private:
int x;
int y;
}; Usuario
(interfaz) CLASE

(155)
Ejemplo

Definir una clase DiaAnyo que contiene los atributos mes y dia y una función miembro
visualizar. El mes se registra como un valor entero en mes (1,Enero,2,Febrero,etc). El
día del mes se registra en la variable entera día. Escribir un programa que haga uso de
la clase y ver su salida.

//uso de la clase DiaAnyo


#include <iostream.h>
class diaAnyo
{
public:
void visualizar();
int mes;
int dia;
};
//programa que usa diaAnyo

int main()
{
diaAnyo, hoy cumpleanyos; //se declaran dos objetos distintos de la clase diaAnyo
cout<<”introduzca fecha del dia de hoy: \n”;
cout<<”introduzca el numero del mes:”;
cin>>hoy.mes; //lecturas
cout<<”Introduzca el dia del mes: ”;
cin>>hoy.dia;
cout<<”Introduzca su fecha de nacimiento: \n”;
cout<<”introduzca el numero del mes:”;
cin<<cumpleanyos.dia;
cout<<”Introduzca el dia del mes: ”;
cin<<cumpleanyos.mes;

cout<<”la fecha de hoy es”;


hoy.visualizar(); //llamada a la función visualizar
cout<<”la fecha de su nacimiento es: ”;
cumpleanyos.visualizar();

if((hoy.mes==cumpleaños.mes)&&(hoy.dia==cumpleanyos.dia))
cout<<”¡Feliz cumpleaños! \n”;
else
cout<<”¡Feliz dia! \n”;

return 1;
}
La implementación de una función miembro externamente a la definición de la clase,
se hace una definición de la función fuera de línea. Su nombre debe ser precedido por
el nombre de la clase y el signo de puntuación :: denominado operador de resolución
de ámbito. El operador :: permite al compilador conocer que fijarx pertenece a la clase
punto y, es por consiguiente, diferente de una función global que pueda tener el
mismo nombre o de una función que tenga ese nombre que puede existir en otra
clase. La siguiente función global, por ejemplo, puede coexistir dentro del mismo
ámbito que Punto::FijarX
(156)
void FijarX(int valx)
{
//. . .
}

El símbolo :: (operador de resolución de ámbitos) se utiliza en


sentencias de ejecución que accede a los miembros estáticos de la
clase. Por ejemplo, la expresión Punto::x se refiere al miembro dato
estático x de la clase Punto.

La palabra reservada inline

La decisión de elegir funciones en línea y fuera de línea es una cuestión de eficiencia


en tiempo de ejecución. Una función en línea se ejecuta normalmente más rápida, ya
que el compilador inserta una copia “fresca” de la función en un programa en cada
punto en que se llama la función. La definición de una función miembro en línea no
garantiza que el compilador lo haga realmente en línea; es un decisión que el
compilador toma, basado en los tipos de las sentencias dentro de la función y cada
compilador C++ toma esta decisión de modo diferente.

Si una función se compila en línea, se ahorra tiempo de la CPU al no tener que ejecutar
una instrucción call para bifurcar a la función y no tener que ejecutar una instrucción
return para retornar al programa llamador. Si una función es corta y se llama cientos
de veces se puede apreciar un incremento en eficiencia cuando actúa como funcion en
línea.

Una función localizada fuera del bloque de la definición de una clase se puede
beneficiar de las ventajas de las funciones en línea si esta precedida por la palabra
reservada inline.

inline void punto::Fijarx(int valx)


{
x=valx;
}

Dependiendo de la implementación de su compilador, las funciones que utilizan la


palabra reservada inline se pueden situar en el mismo archivo de cabecera que la
definición de la clase. Las funciones que no utilizan inline se sitúan en el mismo
modulo de programa, pero no el archivo de cabecera. Estas funciones se sitúan en un
archivo .cpp (.cc, .cxx. .c. etc.).

Nombres de parámetros y funciones miembro:

Al igual que sucede con los prototipos de funciones globales, se pueden omitir los
nombres de parámetros de una declaración de funciones miembro e identificar sólo los
tipo (TDD) de parámetros. Por ejemplo:

(157)
class punto
{
public:
void fijarx(int); // igual a void fijarx(int nombre_de_variable);
void fijarx(int *); // igual a void fijarx(int *nombre_de_apuntador);
};

Sin embargo esta definición no siempre es deseable, ya que como la definición de clase
es también la interfaz de la clase, una función miembro sin más información que los
TDD de parámetros no proporcionara información suficiente sobre como llamar a la
función.

class Demo
{
public:
Funciondemo (int,float,char *,int);
};

Si los nombres de los parámetros aparecen tanto en la declaración como en la


implementación de la función, no es necesario que los nombres sean idénticos pero su
orden tipo si han de serlo:

class punto
{
public:
void girar(int valx,int valy);
// . . .
};

void girar(int x,int y)


{
// . . .
}

Consejo: Es conveniente incluir un comentario de una o dos líneas en la declaración


de una función que indiquen los que hace la función y cuales son los valores de
entrada/salida correspondientes.

Implementación de clases

El código fuente para la implementación de funciones miembro de una clase es código


ejecutable. Se almacena, por consiguiente, en archivos de texto con extensiones .cp,
.cpp, Normalmente se sitúa la implementación de cada clase en un archivo
correspondiente.

Cada implementación de una función tiene la misma estructura general. Obsérvese que
una función comienza con una línea de cabecera que contiene entre otras cosas, el
nombre de la función y su cuerpo esta acotado entre una pareja de signos llave.

Las clases pueden proceder de diferentes fuentes:

(158)
*Se pueden declarar e implementar sus clases propias. El código fuente siempre estará
disponible.

*Se pueden utilizar clases de hayan sido escritas por otras personas o incluso que se
han comprado. En este caso, se puede disponer del código fuente o estar limitado a
utilizar el código objeto de la implementación.

*Se puede utilizar clases de las bibliotecas del mismo programa que acompañan al
software de desarrollo C++. La implementación de estas clases se proporciona siempre
como código objeto.

En cualquier forma, se debe disponer de las versiones de texto de las declaraciones de


clase para que pueda utilizarlas su compilador.

Archivos de cabecera y de clases:

Las declaraciones de clases se almacenan normalmente en sus propios archivos de


código fuente, independientes de la implementación de sus funciones miembro. Estos
son los archivos de cabecera que se almacenan con una extensión .h o bien .hpp en el
nombre del archivo.

El uso de archivos de cabecera tiene un beneficio muy importante “Se puede tener
disponible la misma declaración de clases a muchos programas sin nesecidad de
duplicar la declaración” esta propiedad facilita la declaración de programas en C++, el
cual es un C pero con clases.

Para tener acceso a los contenidos de un archivo de cabecera, un archivo que contiene
la implementación de las funciones de la clase declarada en el archivo de cabecera o
un archivo que crea objetos de la clase declarada en el archivo de cabecera incluye
(include), o mezcla, el archivo de cabecera utilizando una directiva de compilador, que
se una instrucción al compilador que se procesa durante la compilación. Las directivas
del compilador comienzan con el signo “almohadilla” (#).

La directiva que mezcla el contenido de un archivo de cabecera en un archivo que


contiene el código fuente de una función es:

#include nombre_archivo

Opciones de compilación:

Si el archivo de cabecera esta en un directorio diferente entonces se coloca la


ubicación completa en el include:

Ejemplo:

#include <iostream>

utiliza la biblioteca de clases que soporta entrada/salida

#include “\mi_cabezera\cliente.h”

(159)
Constructores

Un constructor es una función miembro de propósito específico que se ejecuta


automáticamente cuando se crea un objeto de una clase. Un constructor sirve para
inicializar los miembros dato de una clase.

Un constructor tiene el mismo nombre que la propia clase. Cuando se define un


constructor no se puede especificar un valor de retorno, ni incluso vid (un constructor
nunca devuelve un valor). Un constructor puede, sin embargo, tomar cualquier numero
de parámetros (cero o más).

Reglas:

1- El constructor tiene el mismo nombre de la clase.


2- Puede tener cero, o más parámetros
3- No devuelve ningún valor.

La clase Rectángulo tiene un constructor con cuatro parámetros:

class Rectangulo
{
private:
int LDerecho;
int LSuperior;
int LInferior;
int LIzquierdo;
public:
Rectangulo(int A,int B,int C,int D); //constructor
//definiciones de otras funciones miembro
};

Cuando se define un objeto, se pasan los valores de los parámetros al constructor


utilizando una sintaxis similar a una llamada normal de la función.

Rectangulo rect(25,25,75,75);

Esta definición crea una instancia del objeto Rectángulo e invoca al constructor de la
clase pasándole los parámetros con valores especificados.

Caso particular

Se puede también pasar los valores de los parámetros cuando se crea una instancia de
una clase utilizando el operador new.

Rectangulo *crect = new Rectangulo(25,25,75,75);

El operador new invoca automáticamente al constructor del objeto que se crea (ésta es
una ventaja importante de utilizar new en lugar de otros métodos de asignación de
memoria tales como la función malloc).

(160)
Constructor por defecto

Un constructor que no tiene parámetros se llama constructor por defecto. Un


constructor por defecto normalmente inicializa los miembros dato asignándoles valores
por defecto.

Ejemplo:

El constructor por defecto en este caso inicializa x y a y en 0.

class Punto
{
public:
Punto() //constructor por defecto
{
X=0;
Y=0;
}
private:
int x;
int y;
};

Ejemplo: Otro constructor alternativo de la clase P, que visualiza un mensaje después


de ser llamado.

Punto::Punto(int valx,int valy)


{
fijarX(valx);
fijarY(valy);
cout<<”Llamado el constructor de Punto .\n”;
}

Constructores sobrecargados

Al igual que se puede sobrecargar una función global, se puede también sobrecargar el
constructor de la clase o cualquier otra función miembro de una clase excepto el
destructor. De hecho los constructores sobrecargados son bastantes frecuentes;
proporcionan medios alternativos para inicializar objetos nuevos de una clase.

Solo un constructor se ejecuta cuando se crea un objeto, con independencia de


cuantos constructores hayan sido definidos.

Ejemplo:

class Punto
{
public:
Punto(); //constructor
Punto(int valx,int valy); //constructor sobrecargados
//…
};
(161)
Declaración de un objeto punto puede llamar a cualquier constructor

Punto P; //llamada al constructor por defecto


Punto Q(25,50); //llamada al constructor alternativo

Constructor de copia:

Existe un tipo especializado de constructor denominado constructor de copia, que se


crea automáticamente por el compilador. El constructor de copia se llama
automáticamente cuando un objeto se pasa por valor: se construye una copia local del
objeto que se construye. El constructor de copia se llama también cuando un objeto se
declara he inicializa con otro objeto del mismo tipo.

Ejemplo:

Punto P;
Punto T(P);
Punto Q=P;

Por defecto, C++ construye una copia bit a bit de un objeto. Sin embargo, se puede
también implementar el constructor de la copia y se utiliza para notificar al usuario
que una copia se ha realizado, normalmente como una ayuda de depuración.

Regla: si existe un constructor alternativo, C++ no generará un constructor por


defecto. Para prevenir a los usuarios de la clase de crear un objeto sin parámetros, se
puede 1) Omitir el constructor por defecto o bien; 2) Hacer el constructor privado en la
clase.

Ejemplo:

class Punto
{
public:
Punto(int valx,int valy);
private:
Punto();
//…
};
...
Punto T; //error el constructor no esta asequible

Inicializacion de miembros en constructores:

No esta permitido inicializar un miembro dato de una clase cuando se define. Por
consiguiente, la siguiente definición de la clase genera errores:

(162)
class C
{
private:
int T=0; //Error
const int Cint = 25; //Error
int &Dint = T; //Error
//…
};

No tiene sentido inicializar un miembro dato dentro de una definición de la clase, dado
que la definición de la clase indica simplemente el tipo de cada miembro dato y no
reserva realmente memoria. En su lugar, se desea inicializar los miembros dato cada
vez que se crea una instancia específica de la clase. El sitio lógico para inicializar
miembros datos, por consiguiente, esta dentro del constructor de la clase. El
constructor de la clase inicializa los miembros dato, por consiguiente, está dentro del
constructor de la clase. El constructor de la clase inicializa los miembros dato
utilizando expresiones de asignación. Sin embargo, ciertos tipos de datos –
específicamente constantes y referencias- no pueden ser valores asignados. Para
resolver este problema, C++ proporciona una característica de constructor especial
Conocido como lista inicializadora de miembros que permite inicializar (en lugar de
asignar) a uno o más miembros dato.

Una lista inicializadota de miembros se sitúa inmediatamente después de la lista de


parámetros en la definición del constructor; consta de un carácter dos puntos, seguido
por uno o más inicializadores de miembro, separados por comas. Un inicializador de
miembros consta del nombre de un miembro dato seguido por un valor inicial entre
paréntesis.

Ejemplo:

class C
{
private:
int T;
const int Cint;
int &Dint;
//…
public:
C(int Param): T (Param), Cint(25), Dint(T)
{
//código del constructor…
}
//…
};

La definición siguiente crea un objeto:

C CObjeto(0);

(163)
con los miembros dato T y CInt se inicializan a 0 y 25, y el miembro dato CInt se
inicializa de modo que se refiere a T.

Diseñar y construir una clase contador que cuente cosas. (Cada vez que se produzca
un suceso al contador se incrementa en 1.) El contador puede ser consultado para
encontrar la cuenta actual.

// contador .cpp
// objeto representa una variable contador
#include <iostream>

class contador
{
private:
unsigned int cuenta; //contar
public:
contador(){cuenta=0;} //constructor
void inc_cuenta(){cuenta++;} //cuenta
void leer_cuenta(){return cuenta;} //devuelve cuenta
};
void main()
{
contador c1,c2;

cout<<”\nc1 = ”<<c1.leer_cuenta();
cout<<”\nc2 = ”<<c2.leer_cuenta();

c1.inc_cuenta();
c2.inc_cuenta();
c2.inc_cuenta();

cout<<”\nc1 = ”<<c1.leer_cuenta(); //visualiza de nuevo


cout<<”\nc2 = ”<<c2.leer_cuenta();
}

La clase Contador tiene un elemento dato: cuenta, del tipo unsigned int (la cuenta
siempre es positivo ya que unsigned actúa como un valor absoluto). Tiene tres
funciones miembro contador(); inc_cuenta(), que añade 1 a cuenta; y leer_cuenta();
que devuelve el valor actual de cuenta.

(164)
Destructores

En una clase se puede definir una función miembro especial conocida como destructor,
que se llama automáticamente siempre que se destruye un objeto de una clase. El
nombre del destructor es el mismo que el nombre de la clase, precedida por el
carácter: ˜ .En este manual se le cambiara por ¿.
Al igual que un constructor, el destructor se puede definir sin ningún tipo de retorno
(ni incluso void); al contrario que un constructor, no puede aceptar parámetros. Sólo
puede existir un destructor.

Ejemplo:

class Demo
{
private:
int datos;
public:
Demo() {datos=0;} //constructor
¿Demo(){} //destructor hall vacío
};

Regla:
*Los destructores no tienen valor de retorno.
*Tampoco tienen argumentos

El uso mas frecuente del destructor es liberar memoria que fue asignada por el
constructor. Si un destructor no se declara explícitamente, C++ crea un vacío
automáticamente.

Si un objeto tiene ámbito local, su destructor se llama cuando su control pasa fuera de
su bloque de definición. Si un objeto tiene ámbito de archivo, el destructor se llama
cuando termina el programa principal (main), Si un objeto se asignó dinámicamente
(utilizando new y delete), el destructor se llama cuando se invoca el operador delete.

//El destructor notifica cuando se ha destruido un punto


class Punto
{
public:
¿Punto()
{
cout <<”Se ha llamado al destructor de punto \n”;
}
// . . .
};

(165)
Sobrecarga de funciones (polimorfismo)

C++ soporta una de las propiedades más sobresalientes en el mundo de la


programación: la sobrecarga. La sobrecarga de funciones permite escribir y utilizar
múltiples funciones con el mismo nombre, pero con diferentes lista de argumentos. La
lista de argumentos es diferente si tiene un argumento con un tipo de dato distinto, si
tiene un número diferente de argumentos, o ambos. La lista de argumentos se suele
denominar signatura de la función.

Consideremos la función cuadrado definida de la forma siguiente:

int cuadrado(int x)
{
return x*x;
}

Si se desea implementar una función similar para procesar un valor long o double y no
se dispone de la propiedad de sobrecarga, se pueden definir funciones independientes
que utilicen un nombre diferente para cada tipo, tal como:

long lcuadrado(long x);


double dcuadrado(double x);

Como C++ soporta sobrecarga se podrían funciones sobrecargadas que tuvieran el


mismo nombre y argumentos diferentes:

int cuadrado(int x);


long cuadrado(long x);
double cuadrado(double x);

En su programa basta con llamar la función cuadrado() con el argumento correcto

long radio=42500;
resultado =cuadrado(radio);

El compilador C++ verifica el tipo de parámetro enviado para determinar cual es la


función a llamar. Así, en la llamada anterior, C++ llama a:

long cuadrado(long x);

ya que el parámetro radio es un TDD long.

(166)
Plantillas de funciones (templates)

Las plantillas de funciones (función templates) proporcionan un mecanismo para crear


una función genérica. Una función genérica es una función que puede soportar
simultáneamente diferentes tipos de datos para su parámetro o parámetros.

Las plantillas son una de las grandes aportaciones de C++. La mayoría de los
fabricantes de compiladores (Borland, Microsoft…) incorporan plantillas (templates).

Las plantillas son muy útiles para los programadores y se emplean cuando se necesita
utilizar la misma función, pero con diferentes tipos de argumentos. Los programadores
que utilizan el lenguaje C resuelven este problema normalmente con macros, sin
embargo, esta solución no es eficiente.

Consideremos por ejemplo la función abs() que devuelva el valor absoluto de su


parámetro. (El valor absoluto de un numero es x si x es mayor que cero, o –x si x es
menor que cero.) para implementar abs(), de modo que pueda aceptar parámetros int,
flota, long y double, se han de escribir cuatro funciones distinta; sin embargo, como
C++soporta funciones sobrecargadas, es posible entonces sobrecargar la función abs
para admitir los cuatro TDD´s citados.

int abs(int x)
{
return (x<0) ? –x : x;
}
int abs(int x)
{
return (x<0) ? –x : x;
}
int abs(int x)
{
return (x<0) ? –x : x;
}
int abs(int x)
{
return (x<0) ? –x : x;
}

Para este tipo de problemas, sin embargo, C++ proporciona un mecanismo más ágil y
potente, las plantillas de funciones. En lugar de escribir las cuatro funciones abs(), se
puede escribir una única plantilla de función, que se decena como:

template <clase <TDD>>


TDD abs(<TDD> x)
{
return (x<0) ? –x : x;
};

La palabra reservada template indica al compilador que una plantilla de función que se
ha definido. El símbolo tipo indica al compilador que puede ser sustituido por el tipo de
dato apropiado: int, float,…,etc.

(167)
Una plantilla de función tiene el siguiente formato:

template <class <TDD>>


declaración de la función

o expresado más en detalle:

template <class <TDD>> <TDD> funcion (<TDD> arg1,<TDD> arg2,…)


{
//cuerpo de la función
}

Algunas declaraciones típicas son:

// 1era FORMA

template <class T> T f(int a,T b)


{
//cuerpo de la función
}

// 2da FORMA

template <class T> T max (T a,T b)


{
return a>b ? a : b;
}

La plantilla función max se declara con un único TDD genérico T y con dos
argumentos.

// 3da FORMA

template <class T1, class T2> T1 max (T1 a,T2 b)

La plantilla función max se declara con dos TDD diferentes posibles. Devuelve un valor
de tipo T1 y requiere dos argumentos: uno de tipo T1 y otro de tipo T2.

Utilización de las plantillas de funciones

La primera operación a realizar consistirá en diseñar una plantilla de función con uno o
varios tipos genéricos T. Una vez diseñada la plantilla de funciones, que puede servir
para manejar cualquier tipo de datos, tales como datos simples, estructuras, punteros,
etc., se puede utilizar ya la plantilla de funciones con un tipo de dato especifico, con lo
que se crea una función de plantillas (estos son términos confusos, pero son los
mismos que Stroustrup utiliza en su libro de C++).

Así por ejemplo, consideremos la función Func1()

(168)
template <class Tipo> Tipo Func1(Tipo arg1,Tipo arg2)
{
//cuerpo de la función Func1
}

void main()
{
int i,j;
float a,b;

//uso de la función Func1() con valores enteros


Func1(i,j);
//uso de la función Func2() con variables float
Func1(a,b);
}

El programa anterior declara una función plantilla Func1() y utiliza la función con
argumentos enteros (int) o reales (float).
Cuando el compilador va la función plantilla, no sucede nada asta que la función se
utiliza realmente en el programa. Cuando la función Func1() se utiliza por primera
vez, se llama con dos argumentos enteros. El compilador examina la función plantilla,
observa que los argumentos se declaran con variables de tipo genéricos y se construye
una función correspondiente que utiliza enteros como argumentos. El compilador
genera la siguiente función real de la función plantilla:

template <class Tipo> Tipo Func1(Tipo arg1,Tipo arg2)


Compilador

int Func1(int arg1, int arg2)


{
//cuerpo de la función Func1
}

El tipo objeto int se utiliza en cualquier parte que la variable Tipo estaba declarada.
Cuando la función Func1() se utiliza la segunda vez con argumentos float, el
compilador genera la siguiente función real de la función plantilla:

float Func1(float arg1, float arg2)


{
//cuerpo de la función Func1
}

(169)
Plantillas de función min y max

El listado minmax.h declara dos plantillas de funciones min() y max().

//minmax.h

#ifdef _ _MINMAX_H
#define _ _MINMAX_H //evita inclusiones múltiples

template <class T> T max(T a,T b)


{
if(a>b)
return a;
else
return b;
}

Template <class T> T min(T a,T b)


{
if(a<b)
return a;
else
return b;
}

#endif

Un programa que utiliza las funciones de plantilla, mediante prototipo que el


compilador utiliza para escribir los cuerpos de las funciones reales:

// Archivo PLANTMMX.CPP

#include <iostream.h>
#include “minmax.h” //archivo de cabecera

int max(int a,int b); //prototipo de función template for int


double max(double a,double b); //prototipo de función template for double
char max(char a,char b); //prototipo de funcion template for char

main()
{
int e1=400, e2=500;
double d1=2.718283, d2=3.141592;
char c1='X', c2='t';

cout<<”maximo(e1,e2) = ”<<max(e1,e2)<<endl;
cout<<”maximo(d1,d2) = ”<<max(d1,d2)<<endl;
cout<<”maximo(c1,c2) = ”<<max(c1,c2)<<endl;
return;
}

(170)
Visibilidad de una función

El ámbito de un objeto (incluido variable) es su visibilidad desde otra parte del


programa y la duración de un objeto es su tiempo de vida, lo que implica que no solo
cuanto tiempo existe la variable, sino cuando se crea y cuando se hace disponible. El
ámbito de un objeto en C++ depende de donde se sitúe la definición y de los
modificadores que la acompañan. En resumen, se puede decir que un objeto definido
dentro de una función tiene ámbito local (alcance local), o si se define fuera de
cualquier función, se dice que tiene ámbito global.

Existen dos clases de almacenamiento en C++: auto y static. Una variable auto es
aquella que tiene una duración automática. No existe cuando el programa comienza la
ejecución, se crea en algún punto durante la ejecución y desaparece en algún punto
antes de que el programa termine la ejecución. Una variable static es aquella que tiene
una duración fija. El espacio para el objeto se establece en tiempo de compilación;
existe en tiempo de ejecución y se elimina solo cuando el programa desaparece de
memoria en tiempo ejecución.

prog_demo.c

Las variables globales declaradas en este


nivel tienen ámbito global. Son validas para
todas las funciones de este archivo fuente a
menos que se utilice la palabra reservada
static.
variable
Funcion_a(); global

Las variables declaradas en este nivel


son locales y tienen clase de
almacenamiento auto al salir de la variable
ejecución, a menos que se utilice la local
palabra reservada static. Visible solo
a esta función.

Las variables con ámbito global se denominan variables globales y son definidas
externamente a la función (declaración externa). Las variables globales tienen el
siguiente comportamiento y atributos:

Las variables globales tienen duración estática por defecto. El almacenamiento se


utiliza en tiempo de compilación y nunca desaparece. Por definición, una variable
global no puede ser una variable auto.

Las variables globales son visibles globalmente en el archivo fuente, se pueden


referenciar por cualquier función, a continuación del punto de definición del objeto.
(171)
Las variables globales están disponibles, por defecto, a otros archivos fuente. Esta
operación se denomina enlace externo.

Variables locales frente a variables globales

Además de las variables globales, es preciso considerar las variables locales. Una
variable local esta definida solamente dentro del bloque o cuerpo de la función y no
tiene significado (vida) fuera de la función respectiva. Por consiguiente, si una función
define una variable como local, el ámbito de la variable esta protegido. La variable no
se puede utilizar, cambiar o borrar desde cualquier otra función sin una programación
especifica mediante el paso de valores (parámetros).

Una variable local es una variable que se define dentro de una función.

Una variable global es una variable que puede ser utilizada por todas las funciones de
un programa dado, incluyendo main().

Para construir variables globales en C++, se deben definir fuera de la función main().
En la figura siguiente la variable global es x0y la variable local es x1. La función puede
realizar operaciones sobre x0, ya que x1 no esta definida fuera del bloque de la función
funcion1(). Cualquier intento de utilizar x1 fuera de funcion1() producirá un error.

int x0; //variable global


funcion1(…) ; //prototipo funcional (o de función)

main()
{



}

Funcion1(…)
{
int x1; //variable local a Funcion1
… //dentro del cuerpo Funcion1

}

Examine ahora la figura siguiente. Esta vez existen dos funciones, ambas definen x1
como variable local. Nuevamente x0 es una variable global. La variable x1 solo se
puede utilizar dentro de dos funciones. Sin embargo cualquier operación sobre x1
dentro de funcion1() no afecta al valor de x1 dentro de funcion2() y viceversa. En
otras palabras, la variable x1 de funcion1() se considera una variable independiente de
la x1 de funcion2().

(172)
int x0; //declaracion y definición de variable
funcion1(); //prototipo de funcion1
funcion2(); //prototipo de funcion2

main()
{



}

funcion1()
{
int x1;



}

funcion2()
{
int x1;



}

Al contrario que las variables, las funciones son externas por defecto, Es preciso
considerar la diferencia entre definición de una función y declaración. Si una
declaración de variable comienza con la palabra reservada extern, no se considera
definición de variable. Sin esta palabra reservada es una definición. Cada definición de
variable es al mismo tiempo una declaración de variable. Se puede utilizar un variable
solo después que ha sido declarada (en el mismo archivo). Únicamente las definiciones
de variables asignan memoria y pueden por consiguiente, contener inicializaciones.
Una variable solo se define una vez, pero se puede declarar tantas veces como se
desee. Una declaración de variable a nivel global (externa a las funciones) es valida
desde esa declaración hasta el final del archivo; una declaración en el interior de una
función es válida solo en esa función. En este punto, considere que las definiciones y
declaraciones de variables globales son similares a las funciones; la diferencia principal
es que se puede escribir la palabra reservada extern en declaraciones de función.

La palabra reservada extern se puede utilizar para notificar al compilador que la


declaración del resto de la línea no esta definida en el archivo fuente actual, pero esta
localizada en otra parte. El siguiente ejemplo utiliza extern:

(173)
//main.cpp

int Total;
extern int Suma;
extern void f(void);
void main(void);

//MODULO.CPP

int Suma;
void f(void);

Utilizando la palabra reservada extern se puede acceder a símbolos externos definidos


en otros módulos. Suma y la función f() se declaran externas

Las funciones son externas por defecto al contrario de las variables.

Variables estáticas y automáticas:

Los valores asignados a las variables locales de una función se destruyen cuando se
termina la ejecución de la función y no se puede recuperar su valor para ejecuciones
posteriores de la función. Las variables locales se denominan variables automáticas,
significando que se pierden cuando termina la función. Se puede utilizar auto para
declarar una variable:

auto int ventas;

Aunque las variables locales se declaran automáticas, por defecto, y por consiguiente
el uso de auto es opcional y, de hecho no se utiliza.

Las variables estáticas (static), por otra parte, mantienen su valor después que una
función se ha terminado. Una variable de una función declarada como estática,
mantiene su valor a través de ejecuciones posteriores de la misma función. Haciendo
una variable local como estática, su valor, se retiene de una llamada a la siguiente de
la función en que esta definida. Se declaran las variables estáticas situando la palabra
reservada static delante de la variable. Por ejemplo:

static int ventas= 10000;


static int dias= 500;

Este valor se almacena en la variable estática, sólo la primera vez que se ejecuta la
función. Si su valor no esta definido, el compilador almacena un cero en una variable
estática por defecto.

(174)
El siguiente programa ilustra el concepto estático de una variable:

#include <iostream.h>
void Ejemplo_estatica(int); //prototipo de la función

void main()
{
Ejemplo_estatica(1);
Ejemplo_estatica(2);
Ejemplo_estatica(3);
}

//ejemplo del uso de una variable estática:

void Ejemplo_estatica(int llamada)


{
static int Cuenta;
cuenta=1;
cout<<”\n El valor de cuenta en llamada n: ”<<llamada<<” es: “<<cuenta;
++cuenta;
}

Al ejecutar el programa se visualiza:

El valor de cuenta en llamada n:1 es: 1;


El valor de cuenta en llamada n:2 es: 2;
El valor de cuenta en llamada n:3 es: 3;

Si quita la palabra reservada static de la declaración de Cuenta, el resultado será:

El valor de cuenta en llamada n:1 es: 1;


El valor de cuenta en llamada n:2 es: 1046;

En donde no se puede predecir cual es el valor de Cuenta en llamadas posteriores.

Las variables globales se pueden ocultar de otros archivos fuente utilizando el


especificados de almacenamiento de clase static.

Para hacer una variable global privada al archivo fuente (y por consiguiente, no útil a
otros módulos de código) se le hace preceder por la palabra static. Por ejemplo, las
siguientes variables se declaran fuera de las funciones de un archivo fuente:

static int m =25;


static char linea_texto[80];
static int indice_linea;
static char buffer[MAXLOGBUF];
static char *pBuffer;

(175)
Las variables anteriores son privadas al archive fuente. Obsérvese este ejemplo:

const OFF=1;
const ON=0;

static unsigned char maestro = OFF;

main()
{
//…
}

function_a()
{
//…
}

maestro se puede utilizar en function_a() como en main(), en este archivo fuente,


pero no se puede declarar como extern a otro modulo fuente.

Se puede hacer también una declaración de función static. Por defecto, todas
las funciones tienen enlace externo y son visibles a otros módulos de programa.
Cuando se sitúa la palabra reservada static delante de la declaración de la función, el
compilador hace privada a la función al modulo fuente. No se puede, entonces
reutilizar el nombre de la función en otros módulos fuente del programa.

Compilación separada:

Hasta este momento, casi todos los ejemplos que se han expuesto en el
capitulo se encontraban en un solo archivo fuente. Los programas grandes son más
fáciles de gestionar si se dividen en varios archivos fuente, también llamados módulos,
cada uno de los cuales puede contener una o más funciones. Estos módulos se
compilan y enlazan por separado posteriormente con un enlazador, o bien con la
herramienta correspondiente del entorno de programación. Cuando se divide un
programa grande en pequeños, los únicos archivos que se recompilan son los que se
han modificado. El tiempo de compilación se reduce, dado que pequeños archivos
fuente se compilan más rápido que los grandes. Los archivos grandes son difíciles de
mantener y editar, ya que su impresión en un proceso lento que utilizara cantidades
excesivas de papel.

(176)
En la figura siguiente se muestra como el enlazador puede construir un
programa ejecutable utilizando módulos objetos cada uno de los cuales se obtiene
compilando un modelo fuente.

Archivo Archivo Archivo


Fuente1 Fuente2 Fuente n

Compilador

Archivo Archivo Archivo Módulos


Objeto1 Objeto2 Objeto n Biblioteca

Enlazador Programa ejecutable

Cuando se tiene más de un archivo fuente, se puede referenciar una función en


un archivo fuente desde una función de otro archivo fuente. Al contrario de las
variables, las funciones son externas por defecto. Si desea, por razones de legibilidad –
no recomendable- puede utilizar la palabra reservada con un prototipo de función y en
una cabecera.

Se puede desear restringir la visibilidad de una función, haciéndola visible sólo a


otras funciones de un archivo fuente. Una razón para hacer esto es reducir la
posibilidad de tener dos funciones con el mismo nombre. Otra razón es reducir el
número de referencias externas y aumentar la velocidad del proceso del enlace.

Se puede hacer una función no visible al exterior de un archivo fuente utilizando


la palabra reservada static. Con la cabecera de la función y la secuencia del prototipo
de función. Se escribe la palabra static antes del tipo de valor(TDD) devuelto por la
función. Tales funciones no serán públicas al enlazador, de modo que otros módulos no
tendrán acceso a ellas. La palabra reservada static, tanto para variables globales como
para funciones, es útil para evitar conflictos de nombres y prevenir el uso accidental de
ellos. Por ejemplo, imaginemos un programa muy grande que consta de muchos
módulos, en el que se busca un error producido por una variable global; si la variable
es estática, se puede restringir su búsqueda al módulo en que esta definida; si no es
así, se extiende nuestra investigación a los restantes módulos en que esta declarada
(con la palabra reservada extern).

(177)
Como regla general, son preferibles las variables locales a las globales. Si
realmente es necesario o deseable que alguna variable, sea global, es preferible
hacerla estática, lo que significa que será “local” en relación al archivo en que está
especificada.

Ejemplo:

//MODULO.CPP

#include <iostream.h>

main()
{
void f(int i), f(void);
extern int n; //declaración de n (no definición)
f(8);
n++;
q();
cout<<”Fin de programa \n”;
}

//MODULO2.CPP

#include <iostream.h>
int n=100; //definición de n, también declaración

static int m=7;

void f(int i)
{
n+=i+m; //n=n+1+i+m, n=(100+1)+8+7;
}

void g(void)
{
cout<<”n =”<<n<<endl;
}

f y g se definen en el modulo 2 y se declaran en el modulo1. Si se ejecuta el


programa, se produce la salida:

n=116;
Fin de programa.

Se puede hacer una función invisible fuera de un archivo fuente utilizando la


palabra reservada static con la cabecera y el prototipo de la función.

(178)
Parámetro const de una función

Con el objeto de añadir seguridad adicional a las funciones, se puede añadir a una
descripción de un parámetro el especificados const, que indica al compilador que sólo
es de lectura en el interior de la función. Si se intenta re_escribir en este parámetro se
producirá un mensaje de error de compilación.

void falso(const int item,const char &car)


{
item=123; //fallo en tiempo de compilación
car='A'; //fallo en tiempo de compilación
}

La tabla siguiente muestra un resumen de los diferentes tipos de parámetros:

Parámetro item pasado Cambia item modifica


especificado por: dentro de la parámetros al
como: función: exterior
int item Valor Si No
const int item Valor No No
int &item Referencia Si Si
cons int &item Referencia No No

Argumentos por omisión:

Como una función tiene un cierto número de parámetros normalmente el mismo


número de argumentos debe indicarse cuando se llama a la función. En C++, sin
embargo.

Una característica poderosa de las funciones C++ es que ellas pueden establecer
valores por omisión o ausencia (“por defecto”) para los parámetros. Se puede asignar
argumentos por defecto a los parámetros que es un argumento por defecto a los
parámetros de una función. Cuando se omite e argumento de un parámetro que es un
argumento por defecto, se utiliza automáticamente éste. La única restricción es que se
deben incluir todas las variables desde la izquierda hasta el primer parámetro omitido.
Si se pasan valores a los argumentos omitidos, se utiliza ese valor, si no se pasa un
valor a un parámetro opcional, se utiliza el valor por defecto como argumento. El valor
por defecto debe ser una expresión constante.

El ejemplo siguiente muestra cómo utilizar argumentos por defecto, en una función
cuyo prototipo es:

void asteriscos(int fila, int col,int num, char c ='*');

Se puede llamar a la function asteriscos de dos formas equivalentes:

asteriscos(4,0,40);

o bien

asteriscos(4,0,40,'*');

(180)
Sin embargo, si se desea cambiar el carácter utilizado por la función se puede escribir:

asteriscos(4,0,40,'#');

En donde el argumento implícito (#) anula el carácter por omisión (*);

Otro ejemplo es la función funcdef()

char funcdef(int arg1=1,char c='A',float f_val=45.7f);

Se puede llamar a funcdef con cualquiera de las siguientes sentencias:

funcdef(9,'Z',91.5); //Anula los tres primeros parámetros (1)


funcdef(25,'W'); //Anula los dos primeros argumentos (2)
funcdef(90); //Anula el primer argumento (3)
funcdef(); //Anula los tres argumentos por defecto (4)

Las sentencias anteriores son equivalentes a:

funcdef(9,'Z',91.5); // ->(1)
funcdef(25,'W',45.7f); // ->(2)
funcdef(90,'A',45.7f); // ->(3)
funcdef(1,'A',45.7f); // ->(4)

Sin embargo, no se puede omitir un argumento a menos que se omitan todos los
argumentos a su derecha. Por ejemplo, la siguiente llamada a la función no es
correcta:

funcdef( ,'Z',99.99); // ERROR!!

Se debe tener cuidado y situar cualquier argumento que tenga valores por defecto a la
derecha de una función.

f();
f(a);
f(a,b);
f(a,b,c);

La función escribir_car tiene dos parámetros. El primero indica el carácter a escribir


(visualizar) y el segundo indica el número de veces que este carácter debe escribirse:

void escribir_car(char c,int num=1)


{
for(int i=1; i<=num;i++)
cout<<c;
}

El parámetro num se la ha dado el valor por defecto de 1. Este valor se utilizará


automáticamente si se omite el argumento correspondiente en una llamada. Si no se
omite el argumento, se utilizara este valor. Llamadas válidas son:

(181)
escribir_car('x',4); //se escribe cuatro veces 'x'
escribir_car('y'); // se escribe una 'y'

El programa ARGDEFEC.CPP muestra cómo asignar valores por omisión a variables


parámetro:

// ARGDEFEC.CPP
// Muestra el uso de valores de parámetros por defecto

#include <iostream.h>

void f(int a=10,int b=20,int c=30)


{
cout<<”a = “<< a<<endl;
<<”b = “<< b<<endl;
<<”c = “<< c<<endl;
}

void main(void)
{
f();
f(1);
f(1,5);
f(1,2,3);
cout<<”Pulse Intro (Enter) para continuar”;
cin.get();
}
Regla de construcción de argumentos por defecto

1- Los argumentos por defecto se deben pasar por valor, Un nombre de un


argumento por defecto no se puede pasar por referencia.
2- Los valores de los argumentos por defecto pueden ser valores literales o
definiciones const. No pueden ser variables. En otras palabras si se declara int
n y a continuación int x = n, se rechazara n como parámetro por defecto, Sin
embargo n si se declara con const int n =1 entonces se acepta la declaración.
3- Todos los argumentos por defecto deben colocarse al final en el prototipo de
función. Después del primer argumento por defecto, todos los argumentos
posteriores deben incluir también valores por defecto

Ejemplo:

Sea la función:

void f(int anchura,float v=3.14159,char x='*');

Las llamadas siguientes son legales:

f(10);
f(10,7.5);
f(10,7.5,'$');

(182)
La llamada siguiente no es legal:

f(10, ,'^');

Ya que se ha intentado saltar uno de los parámetros por defecto.

Otro ejemplo puede ser la función h():

void h(int a=1, int b=2, int c=3, int d=4);

Y llamadas válidas son:

h();
h(9);
h(9,18);
h(9,18,25);
h(9,18,25,4);

Y llamadas no válidas son:

h(9, , ,4);

Ejemplo:

void escribir_car(char c,int num=1,bool lineas_indep= false)


{
for(int i=1;i<num;i++)
{
cout<<c;
if(lineas_indep) // if(lineas_indep==true) siendo una valor
cout<<endl; // booleano
}
}

Algunas llamadas válidas son:

escribir_car('x'); // se escribe una x


escribir_car('#',5); // se escribe 5 # en una sola línea
escribir_car('%',5,true); // se escribe 5 % en líneas independientes

(183)
Detalles de programación básica

Contenidos:

-Ambito
Variables y condicionales
-Dato y función ¿Pueden o no se lo mismo?
-Código de escape
-Operadores de asignación especiales
Operadores de incrementación y decrementación
Asignaciones booleanas
-Operadores de direcciones
-Operador condicional [?]
-Operador coma [,]

Ambito: Se entiende por el espacio, contenido interior entre un par de llaves o


llamado bloque, si este bloque es vacío se le conoce como hall.

Variables y condicionales

Considere el siguiente código:

int main()
{
int A;
if(A==1){}
if(A==2){}
if(A==3){}
}

Por ahora como es lógico A debe tener asignado por defecto cualquier valor y no se
ejecutara ninguno se los condicionales es buena práctica de programación validar las
variables una vez que se declaran siempre, así:

Pseudocodigo

accion principal
entero A;
Aß0;
leer(A).
Si(A=1)entonces
fin_si;
Si(A=2)entonces
fin_si;
Si(A=3)entonces
fin_si;
fin_accion

Las variables locales se declaran fuera de cualquier función y son visibles a todas las
funciones. Las variables locales se declaran dentro de una función y pueden ser
utilizadas por esa función.
(184)
Ejemplo:

int i; //variable global, ambito de programa

static int j; //ámbito de archivo

main()
{
int d,e; //variable local, ámbito de función
//…
}

func(int j)
{
if(j>3)
{
int i; //ámbito de bloque
for(i=0;i<20;i++)
func(i); //instrucción inmediata a for
printf(“HOLA MUNDO”); //se escribe una sola vez fuera de dominio
//de for
}
// i no es visible ya.
}

Obsérvese que func() es una función recursiva por definición se puede llamar a si
misma.

Dato y función ¿Pueden o no se lo mismo?

Este es un dilema de la programación, ya que asta ahora en este manual se ha


definido tanto lo que es un dato y una función pero pueden darse casos en la
programación donde se confunden los conceptos lo cierto es que dicha confusión se
plantea de la forma siguiente:

“Una función puede ser un dato (es una abstracción de la función), pero una dato no
puede ser una función”

Respuesta: Por lo tanto un dato y una función no son lo mismo.

Estructura de una función:

<TDD> <nombre _ función> (<lista de parámetros>)


{
//declaración de variables
//Cuerpo de la función
return <expresion>; //valor devuelto
}

<expresión> puede ser: 0, como en el caso del int main() . Si en lugar de int main(),
fuera una función cualquiera cuyo prototipo fuera: int funcion_suma (int a, int b);
ésta podría implementarse así:
(185)
int funcion_suma(int a, int b)
{
return a+b; //siendo a+d evidentemente una expresión
}

Una función puede retornar una arrays, un puntero a una estructura, o así misma
recursividad.

Advertencia no se pueden declarar funciones anidadas.

Una función puede comportarse como una acción si retorna 0.

Véase la siguiente acción cuadrado() que calcula los cuadrados de numero enteros. A
partir de un numero dado(n).

int cuadrado(int n)
{
int cuadrado=0;
while(cuadrado<=1000) //el cuadrado ha de ser menor o igual que 1000
cuadrado=n*n;
cout<<”El cuadrado de: ”<<n<<” es “<<cuadrado<<endl;
return 0;
}

El ejemplo clásico de que una función puede ser vista como un dato es el siguiente:

int main()
{
int a,b; //declaración de datos locales a main
a=b=0; //inicialización
printf(“Inserte un numero entero: ”);
scanf(“%d”,&a);
printf(“Inserte otro numero entero: ”);
scanf(“%d”,&b);
cuadrado(funcion_suma(a,b)); // funcion_suma(a,b) es vista como un dato
//esta forma de programar es valida. Aunque se
return 0; //calcula el cuadrado de a+b
}

El programa escrito es equivalente a:

int main()
{
int a,b; //declaración de datos locales a main
a=b=0; //inicialización
printf(“Inserte un numero entero: ”);
scanf(“%d”,&a);
printf(“Inserte otro numero entero: ”);
scanf(“%d”,&b);
cuadrado(a+b);
return 0;
}
(186)
Código de escape

(También se conocen como secuencias de escape, véase la página 6 de este manual)

Secuencia de escape Significado


\a Alarma
\b Retroceso de espacio
\f Avance de página
\n Retorno de carro y avance de línea
\r Retorno de carro
\t Tabulación
\v Tabulación vertical
\\ Barra inclinada
\? Signo de interrogación
\” Dobles comillas
\000 Número octal
\x Número hexadecimal
\0 Cero,nulo (ASCII 0)

Operadores de asignacion especiales

Simbolo Uso Descripcion


= a=b Asigna el valor de b a a
*= a*=b a = a*b
/= a/=b a=a/b
%= a%=b a=resto(a/b)
+= a+=b a=a+b
-= a-=b a=a-b
++ a++ (incremento) a=a+1
-- a-- (decremento) a=a-1
** a** a=a*a

Las expresiones ++a y a++ tienen el mismo efecto, como a-- y --a

Operador de negación ( ! ) :

if (A!=B) se lee si a es distinto de b.

Siendo el operador (=) el de asignación y el de (==) el de igualdad

C++ no tiene datos lógicos o booleanos, como Pascal, para representar los valores
verdadero(true) y falso(false). En su lugar se utiliza el tipo int para este propósito, con
el valor entero 0 que representa falso y distinto de cero verdadero.

Asignaciones booleanas o lógicas:

Las sentencias de asignación se pueden escribir de modo que se puede dar un valor de
tipo bool.

(187)
Ejemplo:

bool MayorDeEdad; //declara una variable boleaba


MayorDeEdad=true; //asigna verdad a MayorDeEdad, se valida
MayorDeEdad=(x==y); //asigna el valor de x==y a MayorDeEdad
//si MayorDeEdadßtrue; si a=b; si
//a!=b entonces MayorDeEdad=false;
Las sentencias siguientes asignan valores a dos tipos de variables bool, rango y hez
letra. La variable rango es verdadera (true) y el valor de n esta en el rango -100 a
100, la variable es_letra es verdadera si car es una letra mayúscula o minúscula.

rango=((n>-100)&&(n<100));
es_letra=((('A'<=car)&&(car<='Z'))||(('a'<=car)&&( 'z'<=car)));

En ambas sentencias los valores que booleanos de rango y es_letra dependen de los
valores que puedan tener las variables n y car.

Operadores de direcciones

Son operadores que permiten manipular las direcciones de los objetos:

*expresion
&valor_i (lvalue)
objeto.miembro
puntero_hacia_objeto -> miembro

Operador Acción

*
Lee o modifica el valor apuntado por la expresión. Se
corresponde con un puntero y el resultado es del TDD
apuntado.

&
Devuelve un puntero al objeto utilizado como operando, que
debe ser un Ivalue (variable dotada de una dirección de
memoria). El resultado es un puntero de tipo idéntico al del
operando.

.
Permite acceder a un miembro de un objeto agregado (unión,
estructura o clase)

->
Accede a un miembro de un objeto agregado (unión,
estructura o clase) apuntado por el operando de la izquierda.

Operador condicional ?

El operador condicional, ?: , es un operador ternario que devuelve un resultado cuyo


valor depende de la condición comprobada. Tiene asosiatividad a derechas.

Al ser un operador ternario requiere tres operándoos. El operador condicional se utiliza


para reemplazar a la sentencia if-else lógica en algunas situaciones. El formato del
operador condicional es:

<expresion_c> ? <expresion_v> : <expresion_f>;

(188)
Se evalua la expresion_c y su valor (cero=falso, distinto de cero = verdadero)
determina cuál es la expresión a ejecutar; si la condición es verdadera se ejecuta
expresion_v si es falsa se ejecuta la expresion_f .

La figura siguiente muestra el funcionamiento del operador condicional:

(ventas>150000) ? (comisión=100) : (comisión=0);

Si venta es > 150000 si es menor que 150000


comisión= 100 entonces comisión=0

en ejecución:

comicion=100; comicion=0;

Otros usos del operador :? Son:

n>=0 ? 1 : -1; // 1 si n es positivo, -1 si n es negativo


n>=n ? m : n; // devuelve el mayor entre m y n

La precedencia de ? y : es menor que la de cualquier otro operando tratado hasta ese


momento. Su asociatividad es de derecha.

Operador coma:

El operador coma permite combinar dos o más expresiones separadas por comas en
una sola línea. Se evalúa primero la expresión de la izquierda y luego las restantes
expresiones de izquierda a derecha. La expresión más a la derecha determina el
resultado global. El uso del operador coma es como sigue:

expresion_1, expresion_2, expresion_3,…, expresion_n.

Cada expresión se evalúa empezando desde la izquierda y continuando hacia la


derecha. Por ejemplo, en:

int i=10, j=25;

Dado que el operador coma se asocia de izquierda a derecha, la primera variable está
declarada e inicializada antes que la segunda variable j, Otros ejemplos son:

i++,j++; equivale a i++;j++;


i++,j++,k++ equivale a i++;j++;k++;

El operador coma tiene prioridad de todos los operadores C++, y se asocia de


izquierda a derecha.

(189)
El resultado de la expresión global se determina por el valor de la expresión. Por
ejemplo:

int i,j,resultado;
int j;
resultado=j=10;
i=j;i++;

El valor de i es 11. En primer lugar, a j se asigna el valor de 10, a continuación a i se


le asigna el valor de j. Por ultimo, i se incrementa a 11.

La técnica del operador coma permite operaciones interesantes.

i=10;
j=(i=12,i+8);

Cuando se ejecute la sección de código anterior, j vale 20, ya que i vale 10 en la


primera sentencia, en la segunda toma i el valor 12 y a sumar i=12 con(+) i=8 resulta
i=20.

La biblioteca estándar C++ de funciones en tiempo ejecución incluye gran


cantidad de funciones. Se agrupan por categorías, entre las que destacan:

*manipulación de caracteres
*numéricas
*tiempo y hora
*conversión de datos
*búsqueda y ordenación
*etc.

(190)
Resumen de la programación con clases

*Una clase es un tipo de dato definido por el usuario que sirve para representar
objetos del mundo real.

*Un objeto de una clase tiene dos componentes: un conjunto de atributos y un


conjunto de comportamientos (operaciones). Los atributos se llaman miembros dato y
los comportamientos se llaman funciones miembro.

class circulo
{
double x_centro, y_centro;
double superficie(void);
};

*Cuando se crea un nuevo tipo de clase, se debe realizar dos etapas fundamentales:
determinar los atributos y el comportamiento de los objetos.

*Un objeto es una instancia de una clase.

*Una declaración de una clase se divide en tres secciones: pública, privada, protegida.
La sección pública contiene declaraciones de los atributos y el comportamiento del
objeto que son asequibles a los usuarios del objeto. Se recomienda la declaración de
los constructores en la sección pública. La sección privada contiene las funciones
miembro y los miembros dato que son ocultos o inasequibles a los usuarios del objeto.
Estas funciones miembro y atributos dato son asequibles sólo por la función miembro
del objeto.

*El acceso a los miembros de una clase se puede declarar como privado (private, por
defecto), público(public) o protegido(protected).

class circulo
{
public:
double superficie(void);
void fijar_centro(double x,double y);
void leer_radio(void);
double leer_radio(void);
private:
double centro_x,cemtro_y;
double r;
}

Los miembros dato centro_x, centro_y y r son ejemplos de ocultación de datos.

*Una función definida dentro de una clase, tal como fijar_centro(), se declara
inicialmente en línea (inline). El operador de resolución de ámbito :: se utiliza par
definir una función miembro externa a la definición de la clase .

double circulo::dar_radio(void){return r;}

Las funciones definidas así no son implícitamente inline.


(191)
*Existen dos métodos fundamentales de especificar un objeto.

circulo c; //se crea un objeto de tipo circulo


circulo *ptr_objeto; //se crea un apuntador a un objeto

Y dos métodos para especificar un miembro de una clase:

radio = 10.0; //miembro de la clase


double circulo :: ptr_miembro //puntero a un miembro

Se pueden utilizar dos operadores diferentes para acceder a miembros de una clase:

1- El operador de acceso a miembro (el operador punto)

c.radio=10.0;

2- El operador de acceso a miembro de la clase (el operador flecha)

ptr_objeto->radio=10.0;

3- Un operador puntero a miembro

ptr_objeto à radio=10.0;

*Un constructor es una función miembro con el mismo nombre de su clase. Un


constructor no puede devolver un TDD pero puede ser sobrecargado.

class complejo
// …
complejo(double a,double y);
complejo(const complejo &c)

Para una clase, x, un constructor con el prototipo, x::x(const x&), se conoce como
constructor de copia.

*Un constructor es una función miembro especial que se invoca cuando se crea un
objeto. Se utiliza normalmente para inicializar los atributos de un objeto. Los
argumentos por defecto hacen al constructor más flexible y util.

*El proceso de crear un objeto se llama instanciación (creación de instancia)

*Una función miembro constante es una que no puede cambiar los atributos de sus
objetos. Si se desea utilizar objetos de función clase const, se debe definir funciones
miembro const.

inline double complejo::real(void) const


{
return result;
}

(192)
*Un destructor es una función miembro especial que se llama automáticamente
siempre que se destruye un objeto de la clase.

?complejo(); //en C++ el ? es el acento de la n que la hace ñ

Errores de programación frecuente en POO con clases

Las facilidades en el uso de la estructura clase aumenta las posibilidades de errores.

1. Mal uso de palabras reservadas. Es un error declarar una clase sin utilizar
fielmente una de las palabras reservadas class, struct o unión en la declaración.

2. La palabra reservada class no se necesita para crear objetos de clases. Por


ejemplo, se puede escribir

class C
{

};

C c1,c2; //definiciones de objetos

En lugar de:

class C c1,c2; //no se nesecita class

3. Si un miembro de una clase es privado (private), se puede acceder sólo por


métodos de funciones amigas de la clase. Por ejemplo, éste código no es
correcto:

class c
{
int x;

public:
c()
{
x=-9999;
}
};
void f()
{
C c;
cout<<c.x; // ERROR!!
}

Ya que x es privado a la clase C (por defecto) y la función f no es ni un método ni una


amiga de C

(193)
4. Uso de constructores y destructores.

*No se puede especificar un tipo de retorno en un constructor o destructor, ni en su


declaración ni en su definición. Si C es una clase, entonces no será legal:

void C::C //ERROR


{

}

*De igual modo, no se puede especificar ningún argumento en la definición o


declaración de un constructor por omisión de la clase.

C::C(void) //ERROR
{

}

*Tampoco se pueden especificar argumentos, incluso void, en la declaración o


definición del destructor de una clase.

*No se pueden tener dos constructores de la misma clase con los mismos tipos de
argumentos.

*Un constructor de una clase C no puede tener un argumento de un tipo C, pero sí


puede tener un argumento de tipo referencia, C&. Este constructor es el constructor de
copia.

5. Inicializadores de miembros.

class C
{
//ERROR

int x=5;
};

class C
{
int x;

public:
C()={x=5;}; //correcto
};

6. No se puede acceder a un miembro dato privado fuera de su clase, excepto a través


de una función amiga (friend). Por ejemplo, el código:

class C
{
int x;
};
(194)
int main()
{
C c;
c.x=10; // ERROR, x es privado en t

}

Contiene un error, ya que x es privado en C y por consiguiente asequible sólo por los
métodos o amigas de C.

7. No se puede acceder a un miembro dato protegido (protected) fuera de su


jerarquía de clases, excepto a través de una función amiga. Por ejemplo:

class C // clase base


{
protected:
int x;
};

class D:public C
{

};

int main()
{
C c1;
c1.x=10;
… // ERROR, x es protegido
}

Contiene un error, ya que x solo es accesible por métodos de C y métodos y amigas de


las clases derivadas de C, tales como D.

8. No se pueden sobrecargar ninguno de estos operadores:

. * :: ?: sizeof

9. No se puede utilizar this como parámetro, ya que es una palabra reservada.


Tampoco se puede utilizar en una sentencia de asignación tal como:

this = …; //this es constante ERROR

10. Un constructor de una clase C no puede esperar un argumento de tipo C:

class C;
{

};

(195)
C::C(C c)
{

}

C::C(C &c) // CORRECTO, éste código es una continuación


{

}

11. Un miembro dato static no se puede definir dentro de una clase, aunque sí debe
ser declarado dentro de la declaración de la clase.

class C
{
static int x=7; // ERROR
};
class D
{
static int x;
};

// definición con inicialización

12. Los constructores o destructores no se pueden declarar static.

13. Olvido de punto y coma en definición de clases. Las llaves {} son frecuentes en
código C++, y normalmente no se sitúa un punto y coma después de la llave de
cierre. Sin embargo, la definición de class siempre termina en }; . Un error
típico es olvidar ese punto y coma.

class Producto
{
public:
//…
private:
//…
} // olvido del punto y coma

14. Olvido de inicialización de todos los campos de un constructor. Todo constructor


necesita asegurar que todos los campos (miembros) de datos se fijen en los
valores apropiados.

(196)
class Empleado
{
public:
Empleado();
Empleado(string n); //se olvida el parámetro salario
//…
private:
string nombre;
float salario;
};

15. Referencia a un atributo privado de una clase. Los identificadores declarados


como atributos o funciones privados de una clase no pueden ser referenciados
desde el exterior de la clase. Cualquier intento de referencia producirá mensaje
de error similar a:

“undefined symbol”

16. Fallo por no incluir un archivo de cabecera requerido. Se generan numerosos


mensajes de error por ese fallo de programación ya que un archivo de cabecera
contiene la definición de un número de los identificadores utilizados en su
programa y el mensaje más frecuente de éstos errores séra:

undefined symbol

17. Fallo por definir una función como miembro de una clase. Este error se puede
producir por varias formas:

1- Fallo al prefijar la definición de la función por el nombre de su clase y el


operador de resolución de ámbito (::).
2- Fallo al escribir el nombre de la función correctamente.
3- Omisión completa de la definición de la función de la clase.

En cualquiera de los casos el resultado es el mismo; un mensaje de error del


compilador que indica que la función llamada no existe en la clase indicada.

“is not a member”

Ejemplo: Si se invoca a una función imprimir del objeto c1 de la clase contador en la


sentencia de C++:

c1.imprimir();

Aparece en el programa cliente; se visualizará el mensaje:

“imprimir” if not a member of “contador”

(197)
18. Olvido de punto y coma en prototipos y cabeceras de funciones. La omisión de
un punto y coma al final del prototipo de una función puede producir el mensaje
de error:

“Statement missing”
O bien:

“Declaración terminated incorrectly”

Más sobre el goto

El goto no es una estructura legible de programación, es sustituible por formas


mas entendibles de programación, si se programa y a mitad de la realización del
código hay que colocar un ciclo se pueden presentar complicaciones en el hecho de
que hay que cuidad el orden de las llaves y la colocacion de la comparación o condición
a comparar y ademas de ello el tipo de condicion a comparar si es al principio o al
final. Un goto solventa esta situación de forma rapida aunque esta instrucción debe de
alguna manera ser controlada, se ahorra en tiempo.

etiq1: goto etiq1; //salto de linea


//bloque de instrucciones 1
//bloque de instrucciones etiq1:
//bloque de instrucciones 2
goto etiq1; //ciclo indefinido

//ideal para ensamblador

etiq2: //etiqueta
//bloque de instrucciones 1
goto etiq2; //itera, continue controlado
//bloque de instrucciones opcional 2
goto etiq1; //salto de linea, break controlado
//bloque de instrucciones opcional 3
goto etiq2; //repite ciclo, puede ser controlada
etiq1: //etiqueta de final del ciclo

(198)
Conclusiones

El presente manual contiene información básica para aprender a programar en


C++ y además comprender y gozar de las facilidades que el lenguaje C++ ofrece, el
este lenguaje en materia de programación es un excelente programa con el único
defecto de que no es un lenguaje portable, el lenguaje C++ es un lenguaje muy formal
y se pueden hallar muchas formas de escribir códigos que resuelvan problemas, si se
va a diseñar programas para otros usuarios se tener en cuenta que ciertas funciones
de C++ pueden no ser reconocidas por otros compiladores.

Las funciones son la base de la construcción de programas en C++. Se utilizan


funciones para subdividir problemas grandes en tareas más pequeñas. El
encapsulamiento de las características en funciones, hace los programas más fáciles de
mantener. El uso de funciones ayuda al programador a reducir el tamaño de su
programa, ya que se puede llamar repetidamente y reutilizar el código dentro de una
función.

El entorno de un programa tiene cuatro tipos de ámbito: de programa, archivo


fuente, función y bloque. Una variable está asociada a uno de esos ámbitos y es
invisible (no accesible) desde otros ámbitos.

El programa C++. Un buen programa se obtiene combinando Visual C++ 6.0


con Dev C++, que es un compilador de C/C++ estándar y automáticamente usa
librerías del Visual C++.

Comando útil para el programa: [ Alt Gr+: ] sirve para tener acceso a la
biblioteca del programa.

Insuficiencias del manual:

El manual no presenta información acerca la representaciones de interfaz


graficas en C++, tampoco explica en profundidad el comportamiento y creación de
estructuras de almacenamiento tales como listas, arboles,etc. pero presenta material
abundante sobre punteros, manejo de struct, creación de objetos, manejo de
variables, llamada a funciones. Lo cual constituyen el conocimiento básico para
iniciarse en la creación de estructuras de listas, árboles, presenta además un enfoque
muy orientado al objeto acción, función que se subsana en la recopilación III donde se
explica con mas detalle lo que son las clases nótese que al comienzo de esta
recopilación se plantea un “debate” sobre objeto vs clases muy interesante, se
explica muy poco acerca de los origenes del lenguaje C++ al principio. En fin el
lenguaje C++ es un súper conjunto del lenguaje C como lo podríamos catalogar y este
manual se queda corto. Se omiten además las reglas para la creación de pseudocódigo
ya que esto no forma parte del lenguaje C++, pero en algunas definiciones a manera
general se tomo en cuenta las reglas de representación del pseudocodigo por ejemplo
en la recopilación I. También podría catalogarse de falla el hecho de que algunos
conceptos se repitan en la obra de hecho la recopilación III es material teórico el cual
esta explicado de forma practica en capítulos anteriores, y en la recopilación II
aparezca material que expliquen tópicos ya explicados en la recopilación I, como
apuntadores, no obstante el manual no se diseño con el objetivo de que se lleve un
orden lineal por lo que se recomienda seleccionar el material adecuado a su nesecidad
de programación y implementarlo en su programa, sin embargo el manual contiene
diversas lecturas indispensables para programar en C++.
(199)
Bibliografía consultada:

Recopilación hecha de:

-UCV Profesores: J. Parada #1, J.Jaimes, Robinson, R. Carmona

-Internet….
-Grupo de investigación UCM.
-GUÍA DE SINTAXIS DEL LENGUAJE C++:
(ESTÁNDAR C++ ANSI)
(Fundamentos de Programación guía de L. J. Aguilar)

-Otros cursos por la Web sobre programación en C++, …

-Códigos fuentes/guías para laboratorios de C/C++ UCV.


-tecnun CAMPUS TECNOLÓGICO DE LA UNIVERSIDAD DE NAVARRA
Profesores:
Paúl Bustamante
Iker Aguinaga
Miguel Aybar
Luis Olaizola
Iñigo Lazacano
-Programación en Algoritmos, estructuras de datos y objetos L. Joyanes Aguilar

(200)
La clase string

#include <iostream>
#include <string>
using namespace std;

/*
* inicio de la clase String
*
* uso de una clase string
*/
class String
{
public:
String(); //constructores
String(const char * const);
//constructor de copia
String(const String &);
//destructor
~String();
//operadores sobrecargados
/*operador [] que devuelve una referencia a char. Se utiliza en
instrucciones como UnaCadena[3]=\'x\' */
char & operator[] (unsigned short offset);
//operador [] que devuelve un char. No modifica ningun valor \"const\"
char operator[] (unsigned short offset) const;
String operator+ (const String &);
void operator+= (const String &);
String & operator= (const String &);
//metodos generales
unsigned short GetLen() const
{return itsLen;}
const char * GetString() const
{return itsString;}
private:
//constructor privado, se utiliza unicamente desde alguna funcion interna
de la clase
String (unsigned short);
//declaracion de variables
//contiene la cadena
char * itsString;
//contiene la longitud de la cadena
unsigned short itsLen;
};

//constructor predeterminados. Crea una cadena de 0 bytes


String::String()
{
//inicializamos la cadena
itsString=new char[1];
//colocamos como primera posicion de la cadena el final de linea
itsString[0]=\'\\0\';
itsLen=0;
}

//convierte un array de caracteres en una cadena


String::String (const char * const cString)
{
//strlen=devuelve la longitud de una cadena, sin contar con el caracter nulo de
terminacion.
itsLen=strlen(cString);
itsString=new char[itsLen+1];
//llenamos la cadena con el array recibido
for (unsigned short i=0;i<itsLen;i++)
itsString[i]=cString[i];
itsString[itsLen]=\'\\0\';
}

//constructor de copia
//rhs es una referencia al mismo control String
String::String (const String & rhs)
{
itsLen=rhs.GetLen();
itsString=new char[itsLen+1];
for (unsigned short i=0;i<itsLen;i++)
itsString[i]=rhs[i];
itsString[itsLen]=\'\\0\';
}

//destructor
String::~String()
{
delete [] itsString;
itsLen=0;
}

//operador [] sobrecargado
char & String::operator[] (unsigned short offset)
{
if(offset>itsLen)
return itsString[itsLen-1];
else
return itsString[offset];
}

//operador [] sobrecargado
char String::operator[] (unsigned short offset) const
{
if(offset>itsLen)
return itsString[itsLen-1];
else
return itsString[offset];
}

//crea una cadena nueva al agregar a la cadena actual el contenido de rhs


String String::operator+ (const String & rhs)
{
unsigned short totalLen=itsLen+rhs.GetLen();
//utilizamos el constructor privado \"String (unsigned short);\"
String temp(totalLen);

unsigned short i;
for (i=0;i<itsLen;i++)
temp[i]=itsString[i];
for (unsigned short j=0;j<rhs.GetLen();j++,i++)
temp[i]=rhs[j];
temp[totalLen]=\'\\0\';
return temp;
}

//crea una cadena nueva al agregar a la cadena actual el contenido de rhs. No


devuelve nada, modifica el valor actual.
void String::operator+= (const String & rhs)
{
unsigned short totalLen=itsLen+rhs.GetLen();
//utilizamos el constructor privado \"String (unsigned short);\"
String temp(totalLen);

unsigned short i;
for (i=0;i<itsLen;i++)
temp[i]=itsString[i];
for (unsigned short j=0;j<rhs.GetLen();j++,i++)
temp[i]=rhs[i-itsLen];
temp[totalLen]=\'\\0\';
//modificamos el valor actual de la variable
*this=temp;
}

//operador igual a
String & String::operator= (const String & rhs)
{
//this es una variable que se pasa ocula y hace referencia al lado derecho de la
asignacion (a=b)
//comprovamos si el apuntador del lado derecho de la asignación (this) es igual
a la misma referencia
// de memoria que el lado izquerdo de la asignacion.
if(this==&rhs)
return *this;
//eliminamos la referencia actual de la cadena
delete [] itsString;
//cogemos la nueva longitud
itsLen=rhs.GetLen();
itsString=new char[itsLen+1];
for (unsigned short i=0;i<itsLen;i++)
itsString[i]=rhs[i];
itsString[itsLen]=\'\\0\';
return *this;
}
//constructor privado (ayudante), solo lo utilizan los metodos de la clase
// para crear una cadena nueva del tamaño requerido y llena de caracteres nulos.
//recibe el parametro \'len\', que indica la longitud de la cadena a crear.
String::String (unsigned short len)
{
itsString=new char[len+1];
for (unsigned short i=0;i<=len;i++)
itsString[i]=\'\\0\';
itsLen=len;
}
/*
* fin de la clase
*/

int main()
{
//utilizamos el constructor sobrecargado: \"String(const char * const);\" para
crear la variable s1
String s1(\"prueba inicial\");
cout << \"s1\\t\" << s1.GetString() << endl;

//creamos una variable temporal y la inicializamos


char * temp =\"¡Hola mundo!\";
//utilizamos el operador de copia: \"String & operator= (const String &);\"
s1=temp;
cout << \"s1\\t\" << s1.GetString() << endl;

//definimos una variable char de 30 caracteres


char tempDos[30];
//copiamos el texto \"; ¡es grandioso estar aqui!\" en la variable tempDos
strcpy(tempDos,\"; ¡es grandioso estar aqui!\");
cout << \"tempDos\\t\" << tempDos << endl;
s1+=tempDos;
cout << \"s1\\t\" << s1.GetString() << endl;

cout << \"s1[3]\\t\" << s1[3] << endl;


//modificamos el 4º caracter por una \'x\'
s1[3]=\'x\';
cout << \"s1\\t\" << s1.GetString() << endl;

//intentamos mostrar una posicion de la cadena superior a la largada real de la


misma
//se utilizar el operador sobrecargado [] \"char & String::operator[] (unsigned
short);\"
//devuelve la ultima posición de la cadena
cout << \"s1[999]\\t\" << s1[999] << endl;

String s2(\"otra cadena\");


String s3;
//utilizamos el operador de suma \"String operator+ (const String &);\"
s3=s1+s2;
cout << \"s3\\t\" << s3.GetString() << endl;
String s4;
//utiliza el constructor \"String(const char * const);\"
s4=\"Porque trabaja esta funcion?\";
cout << \"s4\\t\" << s4.GetString() << endl;

//una cadena char normal


char s5[]=\"¡Hola mundo!\";
cout << endl << \"s5\\t\" << s5 << endl;
//modificamos el 4º valor de la cadena
s5[3]=\'x\';
cout << \"s5\\t\" << s5 << endl;
//cualquier posición de memoria... puede contener cualquier caracter
cout << \"s5[100]\\t\" << s5[100] << endl;

return 0;
}

También podría gustarte