Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Manual Sobre El Lenguaje C PDF
Manual Sobre El Lenguaje C PDF
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)
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)
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
Funciones interesantes
fflush(stdin),sizeof,cprintf,kbhit,random,randomize,system
ENUMERACIONES (91)
ESTRUCTURAS DE ALMACENAMIENTO
UNIONES (92)
La sentencia nula en C
Salida
Uso de flujos para salida de caracteres. (102)
Entrada (103)
Manipuladores de C
3En pseudoformal el ” *” se suela cambiar por “^” por lo general y se coloca delante de la
variable, Sintaxis: <nombre_apuntador>^.
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.
“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++
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.
<tipo> <nombre>;
(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).
<tipo> <nombre1>=<valor>,<nombre2>=<valor>,<nombre3>=<valor>;
Tipo de datos:
(3)
Calificadores de tipo
#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.
/*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++
(5)
Secuencias de escape:
\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:
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
#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.
Estructura DO...WHILE
Su sintaxis es:
Do
{
<sentencia1>;
<sentencia2>;
}while (<condición>);
(8)
Ejemplo:
#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>;
}
(9)
Estructura WHILE
Su sintaxis es:
while(<condicion>)
{
<Sentencia1>;
<Sentencia2>;
}
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.
Sentencia printf ( )
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
(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
· 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.
Ejemplo:
*(&h)=42;
(11)
La declaración de un puntero de manera general es:
system("PAUSE");
return EXIT_SUCCESS;
Esta se coloca justo antes de la última llave del main.
Ejemplo:
enum boolean {FALSE, TRUE};
struct Nombre {char primer [10];char segundo[10];};
(12)
Directivas del Preprocesador-> typedef
Ejemplo:
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”
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.
#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);
}
Ejemplo:
#include <stdio.h>
main()
{
int array[25],i;
for (i=0;i<25;i++)
{
printf("Elemento nº %d",i+1);
scanf("%d",&array[i]);
}
visualizar(&array[0]);
}
· declaración o prototipo
void visualizar(int *);
· desarrollo de la función
void visualizar(int *arreglo)
(15)
Su sintaxis es la siguiente:
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]);
}
int numeros[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
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:
printf("%s",dias[i]);
Registros
Concepto de registro
struct <nombre_tipo_estructura>
{
<TDD> <nombre_variable1>;
<TDD> <nombre_variable2>;
<TDD> <nombre_variable3>;
};
struct trabajador
{
char nombre[20];
char apellidos[40];
int edad;
char puesto[10];
};
(17)
Otra forma es:
struct trabajador
{
char nombre[20];
char apellidos[40];
int edad;
char puesto[10];
} fijo, temporal;
<variable>.<campo>;
temporal.edad = 25;
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 notas
{
char nombre[30];
int notas[5];
};
(18)
Registros y funciones
visualizar(fijo);
Ejemplo:
#include <stdio.h>
struct trabajador
{
char nombre[20];
char apellidos[40];
int edad;
char puesto[10];
};
(19)
2.- Por referencia: su declaración sería:
visualizar (&fijo);
Ejemplo:
#include <stdio.h>
struct trabajador
{
char nombre[20];
char apellidos[40];
int edad;
char puesto[10];
};
(20)
Arreglos de registros
struct trabajador
{
char nombre[20];
char apellidos[40];
int edad;
};
Definición de tipos
struct trabajador
{
char nombre[20];
char apellidos[40];
int edad;
};
(21)
Otra forma:
typedef struct
{
char nombre[20];
char apellidos[40];
int edad;
}trabajador datos;
Archivos
Apertura de archivos
Su sintaxis es:
FILE *<nombre_del_puntero>;
puntero = fopen (<nombre del archivo>, "<modo de apertura>" );
Algunos ejemplos:
puntero = fopen("DATOS.DAT","r");
puntero = fopen("C:\\TXT\\SALUDO.TXT","w");
Modo texto
(22)
Modo binario
Un ejemplo:
FILE *pf;
pf=fopen("datos.txt","r");
if (pf == NULL) printf("Error al abrir el archivo");
Su sintaxis es:
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();.
fclose(<nomb_puntero>);
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
Un carácter:
fputc(<variable_caracter>,<puntero_archivo>);
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);
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>);
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);
}
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>);
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);
}
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>);
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);
}
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
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
Ejemplo:
(29)
Ejemplo:
int i = 3, j = 50;
intercambio (i, j);
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:
(30)
Resumen sobre las librerías de C
ifstream canal_entrada;
ofstream canal_salida;
canal_entrada.open(“nombre_archivo_texto_entrada”);
canal_salida.open(“nombre_archivo_texto_salida”);
ifstream canal_entrada(“nombre_archivo_texto_entrada”);
ofstream canal_salida(“nombre_archivo_texto_salida”);
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:
class <nombre_clase>
{
// miembros de datos
public: //puede ser private o protected
// funciones / objetos miembros
} // lista_objetos
(32)
Control de acceso a miembros (CDA)
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;
Archivos de cabecera
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.
Ejemplo:
/* Declaración de funciones. */
#include <stdio.h>
main()
{
int num=10; /* variable local */
printf("%d\n",num);
funcion(); /* llamada */
}
void funcion(void)
{
printf("%d\n",num);
}
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:
(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>
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 */
}
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:
(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;}
};
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
#include <iostream.h>
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;
}
• 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.
/*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();
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.
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.
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.
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>);
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 */
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.
Función principal
Funcion(es) auxiliares
Apuntador
Expecificador de formato
SINTAXIS: (<TDD>)<expresión>;
SINTAXIS: <TDD>(<expresión>);
(44)
Ejemplo: Leer un registro y guardar la primera línea tipo carácter en entero.
//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
(45)
Excepciones en C
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";
}
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();
}
DECLARACIÓN:
{<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();
}
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:
{
<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();
}
(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();
}
(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();
}
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();
}
~<nombre_función>(<parámetros>);
(54)
DESARROLLO DE LA FUNCION:
<nombre_clase>::<nombre_función>()
{
<cuerpo>;
}
#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();
}
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();
}
(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();
}
PROTOTIPO:
(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
.
::
¿??
.*
(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);
};
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();
}
(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);
};
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();
}
(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 )
=,≠ (Relación)
--> (Asignación) _
(62)
Funciones InLine y Automáticas
Sintaxis:
#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";
}
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";
}
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];
};
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();
}
(65)
EJEMPLO:
#include <stdio.h>
#include <conio.h>
class miclase{
int a;
public:
void pasar_a(int num);
int mostrar_a();
};
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();
}
Sintaxis:
(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();
}
SINTAXIS:
SINTAXIS:
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();
}
#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
EJEMPLO:
//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();
}
(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
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.
(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();
}
(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*/
}
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.
#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;}
};
{
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();
}
#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;}
};
(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.
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";}
};
(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.
PROTOTIPO: (sintaxis)
DESARROLLO:
{
<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);
};
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
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:
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.
(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.
*(&h)=42;
int *ip;
double *dp;
(80)
SINTAXIS La declaración de un puntero de manera general es:
<tipo> *<nombre_de_apuntador>(<variable>);
(81)
La Aritmética de Apuntadores.
Generalidades:
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.
(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
(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.
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.
<tipo> <nombre_del_arreglo>[<tamaño_indice>];
<tipo> <nombre_arreglo_bidimensional>[<tamaño_fila>][<tamaño_columna>];
(85)
Estos también se pueden inicializar:
Ejemplo:
int grande[3][4][7];
ó incluso
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.”
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.
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*/
ptr =+3; /* ptr = ptr + 3, suma 3 a ptr; ptr apunta al 4to elemento de arr*/
pa=&a[0];
*pa=a[0];
/*y*/
*(pa+1)=a[1];
(87)
M O Y
0 1 2 3 4 5 6 7 8 9
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];
}
(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
Constantes de cadena
Su declaración es similar a:
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
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:
delete prt1;
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
ENUMERACIONES
enum <nombre>{<valor_1>,<valor_2>,<valor_3>,…,<valor_n>};
ESTRUCTURAS
(91)
La sintaxis de una estructura es:
struct <nombre>{<miembro_1>;<miembro_2>;…;<miembro_n>};
struct cuadro
{
int i;
float f;
};
struct cuadro nombre; /*Estilo C cuadro es una variable del TDD cuadro*/
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>};
union alfa
{
int x;
char o;
};
alfa w;
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;
}
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++
#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
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
(94)
Llamadas a la función ImprimirValores:
ImprimirValores (n,a);
ImprimirValores (n); //equivalente a ImprimirValores (n, 0.0)
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:
(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:
(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:
(97)
Paso de 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
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:
#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:
#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)
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:
char cad[80]=”Cazorla”;
int i;
for (i = 0; cad[i] != ‘\0’; i++);
(100)
Prioridad y asociatividad de operadores en C (versión completa)
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.
:: ( ) [ ] . -> 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
(101)
ENTRADAS Y SALIDAS BÁSICAS
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.
cout << i;
#include <iostream.h>
int main()
{
cout << “Hola Mundo\n”;
}
#include <isostrean.h>.
int main()
{
int i;
i = 1099;
cout << ”El valor de i es” << i << “\n”;
}
#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
cin >> i;
#include <iostream.h>
int main()
{
int i;
cin >> i;
cout << i;
}
#include <iostream.h>
int main()
{
char c[60];
int x,y;
cin >> c >> x >> y;
cout << c << “ “ << x << “ “ << y << “\n”;
}
Manipuladores
#include <iostream.h>
int main ()
{
int i = 36;
cout << dec << i << oct << i << “ ” << hex << i << “\n”;
}
(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++
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.
C posee los mismos tipos de datos primitivos que Java, estos son int, float,
char, bool*, double.
Hexadecimal:
int x = 0xAA; /* asigna el valor 170 en hex (se antecede con un 0x)*/
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:
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.
continue: Usada para ignorar todas las instrucciones en el bloque que se encuentran
después de esta instrucción.
D) Instrucciones de Preprocesador:
#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
Ejercicio:
***Desarrollar una función factorial (recursiva) en C.***
-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:
-Ldirectorio
-Itrayectoria
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:
Parámetros:
Ejemplo:
int variable = 0;
fscanf(STDIN,”%d”,&variable);
• %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.
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:
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.
float matrix[<N_FILAS>][<N_COL>];
char cadena[<TAMAÑO>];
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
Persona persona1;
Persona ptr*;
ptr = &persona1;
Para acceder a las propiedades de persona por medio del apuntador puede
usarse el operador de dereferenciación (->)
(111)
Laboratorio #2 de C
Una vez declarado un puntero a archivo utilizaremos la función fopen(). Para abrir
el archivo y asociarlo al puntero.
Su sintaxis es:
Algunos ejemplos:
puntero = fopen("DATOS.DAT","r");
puntero = fopen("C:\\TXT\\SALUDO.TXT","w");
Modo texto
Un ejemplo:
FILE *pf;
pf=fopen("datos.txt","r");
if (pf == NULL) printf("Error al abrir el 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( );.
fclose(puntero);
FILE *pf;
pf = fopen("AGENDA.DAT","rb");
if ( pf == NULL )
printf ("Error al abrir el archivo");
else
fclose(pf);
do {
c = fgetc (pFile);
if (c == '\n') i++;
} while (c != EOF);
int fread (void *buffer, size_t size, size_t count, FILE *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.
Escribir un 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
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.
2. Sintaxis C++
(115)
2.1 Clases
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:
(116)
Modificadores de Acceso (MDA)
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 “
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.
(117)
Los métodos invocados pertenecen al objeto y modifican el estado del objeto.
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.
Nombretipo *ptrNuevo;
ptrNuevo = malloc (sizeof(nombretipo));
void free (void *memblock)
Free (ptrNuevo);
delete PrtNuevo
(118)
Actividad nro 1.
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
10 cdrom 85000
15 floppy 30000
2 monitor 350000
(119)
Sentencias de salto:
Sintaxis:
sentencias …
…
if(condición)
goto salto;
sentencia_1;
sentencia_2;
…
}
salto:
sentencia_3;
sentencia_4;
…
Para más información sobre break y continue consulte la página 140 de ciclos
infinitos de C++.
(120)
SOBRE ALGUNOS OPERADORES:
Operador coma(,)
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.
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
}
(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.
(122)
Estructuras de almacenamiento:
Programa:
struct alumno
{
char nombre[31];
char direccion[21];
unsigned long no_matricula;
unsigned long telefono;
float notas[10];
};
Programa:
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;
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
}
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.
alumnos *pt;
pt = &nuevo_alumno;
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
Sintaxis:
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.
delete[] vector;
(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;
}
#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
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.
dia1 = martes;
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.
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
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.
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>
(129)
Creación de un objeto en C++
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)
{
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");
}}}}}
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*/
(138)
Recursividad en C++
factorial(5,0);
(139)
Los ciclos infinitos de C++ (uso de palabras break y continue)
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:
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:
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:
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:
while (opcion<4)
{
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:
Este error ocurre porque se esta saltando el incremento por lo que en ciclos la
sentencia continue debe colocarse después del incremento.
(142)
n=0;
while(1)
{
opcion++;
/*
.
conjunto de intrucciones que se ejecutaran n veces
.
.
*/
if(opcion==n)break;
}
opcion=0;
while(1)
{
opcion++;
if(opcion==2)
{
printf("->SIN PERMISO");
break;
}else{
printf("->CON PERMISO");
}
}
“YO ENTRO SIEMPRE ->CON PERMISO YO ENTRO SIEMPRE ->SIN PERMISO "
opcion=n;
while(1)
{
/*
.
conjunto de instrucciones que se ejecutaran n+1 veces
.
.
*/
if(opcion<n){opcion++;}else break;
}
Instrucciones inmediatas:
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
(144)
Paso de punteros y variables a objetos
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;
return 0;
}
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*.
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.
Los arrays sempre se pasan por referencia ya que lo que realmente se pasa es la
direccion de memoria del primero elemento del arreglo.
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:
Entrada / Salida
*Archivos
La primera operación sobre un archivo antes de usarlo es abrirlo:
*Para abrir un archivo se debe declarar un (file pointer) que apunta a un escritura del
tipo FILE.
(148)
Variables vs Apuntadores
Nota: *C y A ambos son variables. Mientras que C y &A, ambos indican una posición
de memoria especifica de memoria.
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”
“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”
(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”.
*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
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.
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;
};
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:
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.
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;
CLASE
No asequibles
desde el exterior Privado
de la clase
(acceso denegado) Datos o funciones
(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.
class estudiante
{
long numid;
char nombre[40];
int edad;
public:
long leerNumid();
char *Leernombre();
int leeredad();
};
(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:
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”;
}
// . . .
};
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.
*Operadores que permiten definir operadores estándar C++ para los objetos de las
clases.
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.
(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.
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;
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)
{
//. . .
}
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.
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);
};
class punto
{
public:
void girar(int valx,int valy);
// . . .
};
Implementación de clases
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.
(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.
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” (#).
#include nombre_archivo
Opciones de compilación:
Ejemplo:
#include <iostream>
#include “\mi_cabezera\cliente.h”
(159)
Constructores
Reglas:
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
};
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.
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
Ejemplo:
class Punto
{
public:
Punto() //constructor por defecto
{
X=0;
Y=0;
}
private:
int x;
int y;
};
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.
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
Constructor de copia:
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.
Ejemplo:
class Punto
{
public:
Punto(int valx,int valy);
private:
Punto();
//…
};
...
Punto T; //error el constructor no esta asequible
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.
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…
}
//…
};
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();
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.
(165)
Sobrecarga de funciones (polimorfismo)
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 radio=42500;
resultado =cuadrado(radio);
(166)
Plantillas de funciones (templates)
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.
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:
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:
// 1era FORMA
// 2da FORMA
La plantilla función max se declara con un único TDD genérico T y con dos
argumentos.
// 3da FORMA
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.
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++).
(168)
template <class Tipo> Tipo Func1(Tipo arg1,Tipo arg2)
{
//cuerpo de la función Func1
}
void main()
{
int i,j;
float 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:
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:
(169)
Plantillas de función min y max
//minmax.h
#ifdef _ _MINMAX_H
#define _ _MINMAX_H //evita inclusiones múltiples
#endif
// Archivo PLANTMMX.CPP
#include <iostream.h>
#include “minmax.h” //archivo de cabecera
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
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 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:
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.
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.
(173)
//main.cpp
int Total;
extern int Suma;
extern void f(void);
void main(void);
…
//MODULO.CPP
int Suma;
void f(void);
…
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:
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:
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);
}
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:
(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()
{
//…
}
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.
Compilador
(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
void f(int i)
{
n+=i+m; //n=n+1+i+m, n=(100+1)+8+7;
}
void g(void)
{
cout<<”n =”<<n<<endl;
}
n=116;
Fin de programa.
(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.
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:
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,'#');
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:
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);
(181)
escribir_car('x',4); //se escribe cuatro veces 'x'
escribir_car('y'); // se escribe una 'y'
// ARGDEFEC.CPP
// Muestra el uso de valores de parámetros por defecto
#include <iostream.h>
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
Ejemplo:
Sea la función:
f(10);
f(10,7.5);
f(10,7.5,'$');
(182)
La llamada siguiente no es legal:
f(10, ,'^');
h();
h(9);
h(9,18);
h(9,18,25);
h(9,18,25,4);
h(9, , ,4);
Ejemplo:
(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 [,]
Variables y condicionales
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:
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.
“Una función puede ser un dato (es una abstracción de la función), pero una dato no
puede ser una función”
<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.
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
}
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
Las expresiones ++a y a++ tienen el mismo efecto, como a-- y --a
Operador de negación ( ! ) :
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.
Las sentencias de asignación se pueden escribir de modo que se puede dar un valor de
tipo bool.
(187)
Ejemplo:
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
*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 ?
(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 .
en ejecución:
comicion=100; comicion=0;
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:
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:
(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++;
i=10;
j=(i=12,i+8);
*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.
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.
*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;
}
*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 .
Se pueden utilizar dos operadores diferentes para acceder a miembros de una clase:
c.radio=10.0;
ptr_objeto->radio=10.0;
ptr_objeto à radio=10.0;
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.
*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.
(192)
*Un destructor es una función miembro especial que se llama automáticamente
siempre que se destruye un objeto de la clase.
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.
class C
{
…
};
En lugar de:
class c
{
int x;
…
public:
c()
{
x=-9999;
}
};
void f()
{
C c;
cout<<c.x; // ERROR!!
}
(193)
4. Uso de constructores y destructores.
C::C(void) //ERROR
{
…
}
*No se pueden tener dos constructores de la misma clase con los mismos tipos de
argumentos.
5. Inicializadores de miembros.
class C
{
//ERROR
int x=5;
};
class C
{
int x;
…
public:
C()={x=5;}; //correcto
};
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.
class D:public C
{
…
};
int main()
{
C c1;
c1.x=10;
… // ERROR, x es protegido
}
. * :: ?: sizeof
class C;
{
…
};
(195)
C::C(C c)
{
…
}
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;
};
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
(196)
class Empleado
{
public:
Empleado();
Empleado(string n); //se olvida el parámetro salario
//…
private:
string nombre;
float salario;
};
“undefined symbol”
undefined symbol
17. Fallo por definir una función como miembro de una clase. Este error se puede
producir por varias formas:
c1.imprimir();
(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:
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
Comando útil para el programa: [ Alt Gr+: ] sirve para tener acceso a la
biblioteca del programa.
-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)
(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 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];
}
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;
}
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;
return 0;
}