You are on page 1of 114

LIBRO 1

Indice.

1. Programación orientada a objetos. Usando C++.


Notación Húngara.
Secuencias de escape y de control : \n \t \a \\ \”
Código ASCII
Equivalencias decimal – hexadecimal – octal - binario
Tipos de Datos.
• Asignar un valor a una varible.
• Conversion de tipos en una operación.
o INTDOUBLE.
• Operaciones con tipos de datos diferentes.

2.1. int
2.2. Uso de cadenas de caracteres.
• Char.
2.3. float y double.
2.4. void.
2.5. enum.
2.6. struct.
2.7. const.
2.8. typedef.
2.9. bool.
3. Apuntadores o punteros.
• Apuntadores a cadenas.
• Apuntador NULL.
• Punteros a estructuras ( ->).
• Variables dinámicas con punteros - Memoria dinámica.
o New,
o delete.
4. Declaraciónes.
Variables.
Funciones.

5. Arreglos, Arrays o Matrices.


Arreglos simples.
Arreglos multidimensionales.
Pasando arreglos a funciones.

Librería Vector- Array.


Librería Map – Matrices asociativas.

goto

6. Estructuras de Control.
Proposiciones condicionales.
If if-else if-else if- else if - else
Switch.
7. Proposiciones iterativas.
7.1 for.
7.2 while.
7.3 Do.
8. Operadoredes.
Operadores unuarios.
Operador binario.
Operadores lógicos.
Operadores sobrecargados.
Otros Operadores.
# define  Operador de preprocesador
• Creación de macros.
1
• La directiva "#include"
10. Funciones
10.1 Llamadas por valor y llamadas por referencia.
Inline. Funciones en línea.
11. Clases.
Acceso a variables miembro mediante “.” o “ ->”.
Herencia. Clases Heredadas.
Polimorfismo. Virtual.
Clases y Estructuras Anidadas.
Variables Miembro
Funciones amigas o friendo.
Template – Plantillas.
Constructores y destructores.
Librerías. Organización de archivos
Uso de librerías.
Encabezado de Archivos .h
Archivos fuente .cpp

16. Entrada y salida en C++


Entrada y salida de archivos
Vocabulario.
Formatos.

2
1. Fundametos de la programación orientada a objetos.
La programación orientada a objetos (OOP) se basa en la noción referente a los objetos del mundo real para
desarrollar aplicaciones.

También se pueden relacionar clases individuales en una jerarquía de clases. Los fundamentos de la OOP
incluyen clases, objetos, mensajes, métodos, herencia y polimorfismo.

Una clase define una categoría de objetos. Cada objeto es una instancia de una clase.

Clases y objetos

Un objeto comparte los mismos atributos y la misma funcionalidad con los demás objetos de la misma clase.
Normalmente, un objeto tiene un estado único, definido por los valores actuales de sus atributos. La
funcionalidad de una clase determina las operaciones posibles para las instancias de esa clase. El C++ hace
llamadas a los atributos de los datos miembro de la clase y a las operaciones de las funciones miembro de la
clase. La clase encapsula los datos miembro y las funciones miembro. Si regresamos al ejemplo del reloj
CASIO, los botones del reloj representan las funciones miembro de la clase de relojes CASIO y lo que
aparece en la pantalla de los mismos representa un dato miembro. Puedo oprimir determinados botones para
editar la fecha y la hora. En términos de la OOP, las funciones miembro modifican el estado del objeto y
cambian sus datos miembro.

Herencia

En los lenguajes orientados a objetos, se puede derivar una clase a partir de la otra.

Con la herencia, la clase deriva (también llamada clase descendiente), hereda los datos miembro y funciones
miembro de sus clases padre y ancestro

Derivar una clase refina a la clase padre, pues le añade nuevos atributos y nuevas operaciones. La clase
derivada declara, por lo general, nuevos datos miembro y nuevas funciones miembro heredadas cuando las
operaciones de estas funciones no son adecuadas para la clase derivada.

Para aplicar el concepto de herencia al reloj Data Bank de Casio, considere la siguiente situación posible.
Supongamos que el fabricante de relojes decide crear un reloj Data Comm de Casio, que proporcione las
mismas características del Data Bank de CASIO, y además, un timbre de aviso o alarma. En lugar de diseñar
el nuevo modelo (esto es, la nueva clase en términos de la OOP) a partir de cero, los ingenieros de CASIO
comienzan con el diseño existente del Data Bank de Casio Y construyen el nuevo a partir de él. Quizás este
proceso añada nuevos atributos y operaciones al diseño existente y modifique algunas operaciones
existentes para que se ajusten al nuevo diseño. Por lo tanto, el modelo Data Comm de CASIO hereda los
atributos y las operaciones del modelo Data Bank de CASIO. En términos de la OOP, la clase de relojes Data
Comm de CASIO es descendiente de la clase de relojes Data Bank de CASIO.

Mensajes y métodos

La programación orientada a objetos modela la interacción con los objetos como eventos cuando son
enviados mensajes a un objeto o entre objetos. El objeto que recibe un mensaje responde llamando al
método adecuado (esto es, a la función miembro en el C++).

El mensaje es lo que se le hace a un objeto. El método es la forma en que el objeto responde al mensaje
recibido.

Polimorfismo

La característica de polimorfismo de la OOP permite que las instancias de diferentes clases reaccionen de
forma particular a un mensaje (o llamada a función, en términos del C++). Por ejemplo, en una jerarquía de
formas gráficas (punto, línea, cuadro, rectángulo, elipse, etc.) cada forma tiene la función Trazar, la cual está
obligada a responder adecuadamente a una petición para dibujar la forma.

El polimorfismo permite que instancias de diferentes clases respondan a la misma función en formas que
sean adecuadas para cada clase.

3
Sentencia. Es una declaración simple, comando o cálculo que termina con un unto y como.

Ejemplo: char valriable=”Hola”;

4
Notación Hungara.

La notación húngara es una serie de normas para escribir un programa.


Variables. Prefijos en minúsculas que se añaden a los nombres de las variables que indican su tipo.
Tipos definidos. Las letras del prefijo estarán en mayúscula. El resto del nombre indica, lo más claramente
posible, la función que realiza la variable o tipo.

Prefijo Significado
a 'array'.
b Booleano
by BYTE o UCHAR (unsigned char)
c Carácter (un byte) 'char'. Para el tipo primitivo de carácter alfanumérico individual.
d 'double'. Para tipos numéricos de alta precisión, como double o float.
dw Entero largo de 32 bits sin signo (DOBLE WORD)
e 'event'. Para eventos.
'función'. Sólo la utilizaremos delante de funciones cuando se traten de funciones que se añadan
f como observadores de un evento (ya que usar esta notación para cualquier método o función
sería bastante engorroso).
g 'delegated'. Para tipos delegados.
h Manipulador de 16 bits (HANDLE)
i Entero largo de 32 bits
De 'lock'. Para objetos de control que nos faciliten el uso de exclusiones mutuas, candados y
l
semáforos.
lp Puntero a entero largo de 32 bits
lbl Objeto Label
lpfn Puntero largo a una función que devuelve un entero
lpsz Puntero largo a una cadena terminada con cero
n 'enum'. Para tipos enumerados.
'objeto'. Para objetos en general (no se debe usar la notación húngara para distinguir entre tipos
o
de objetos, salvo escasas excepciones).
p Puntero a entero de 16 bits
pt Coordenadas (x, y) empaquetadas en un entero de 32 bits
rgb Valor de color RGB empaquetado en un entero de 32 bits
'string'. Para variables de tipo cadena de texto, ya sean nativos o arrays de char. Este tipo de
s datos es muy habitual en lenguajes sin lógica de punteros. Si se usara el objeto de tipo “String”
en estos casos, acudiremos a este identificador en lugar de al ‘o’ de objeto.
sz Cadena terminada en cero
'struct'. Similar al 'o' de objetos, éste se usaría para variables de tipo struct en general (es decir,
t
objetos de tipo primitivo).
txt Cajas de texto
u Sin signo (unsigned)
'variable'. Para variables que adquieran diferentes tipos de valores. Normalmente sólo
acudiremos a esta opción en lenguajes no tipados. La usaremos cuando no estemos seguros del
v
tipo de valor que albergará una variable. También puede valer para objetos que tengan un tipo
genérico T.
w Entero corto de 16 bits sin signo (WORD)
y 'byte'.

5
Ejemplos:
nContador: la variable es un entero que se usará como contador.
szNombre: una cadena terminada con cero que almacena un nombre.
bRespuesta: una variable booleana que almacena una respuesta.

Ejemplos de tipos definidos por el API de Windows:


UINT: entero sin signo. Windows redefine los enteros para asegurar que el tamaño en bits es
siempre el mismo para todas las variables del API.
LRESULT: entero largo usado como valor de retorno.
WPARAM: entero corto de 16 bits usado como parámetro.
LPARAM: entero largo de 32 bits usado como parámetro.
LPSTR: puntero largo a una cadena de caracteres. En el API de 32 bits no existen distinciones entre
punteros largos y cortos, pero la nomenclatura se conserva por compatibilidad.
LPCREATESTRUCT: puntero a una estructura CREATESTRUCT.

6
1.2 Secuencias de escape :

Escape Represents
Sequence
\a Alerta. 1 pitido de la cpu. Bell (alert)
\b Backspace
\f Formfeed
\n Pasar a la siguiente línea inferior.New line
\r Carriage return
\t Equivale al tabulador.Horizontal tab
\v Vertical tab
\' Single quotation mark
\" Comillas dobles “ (El simbolo)Double quotation mark
\\ Diagonal invertida  \ (El simbolo). Backslash

\? Literal question mark


\ooo ASCII character in octal notation
\xhh ASCII character in hexadecimal notation
\xhhhh Unicode character in hexadecimal notation if this escape sequence is used in a wide-
character constant or a Unicode string literal.
For example, WCHAR f = L'\x4e00' or WCHAR b[] = L"The Chinese character for
one is \x4e00".

7
ASCII

8
9
Como usar este codigo.

Ejemplo:

10
Equivalencias decimal – hexadecimal – octal - binario

Dec Hex Oct Bin Dec Hex Oct Bin Dec Hex Oct Bin Dec Hex Oct Bin
0 0 000 00000000 16 10 020 00010000 32 20 040 00100000 48 30 060 00110000
1 1 001 00000001 17 11 021 00010001 33 21 041 00100001 49 31 061 00110001
2 2 002 00000010 18 12 022 00010010 34 22 042 00100010 50 32 062 00110010
3 3 003 00000011 19 13 023 00010011 35 23 043 00100011 51 33 063 00110011
4 4 004 00000100 20 14 024 00010100 36 24 044 00100100 52 34 064 00110100
5 5 005 00000101 21 15 025 00010101 37 25 045 00100101 53 35 065 00110101
6 6 006 00000110 22 16 026 00010110 38 26 046 00100110 54 36 066 00110110
7 7 007 00000111 23 17 027 00010111 39 27 047 00100111 55 37 067 00110111
8 8 010 00001000 24 18 030 00011000 40 28 050 00101000 56 38 070 00111000
9 9 011 00001001 25 19 031 00011001 41 29 051 00101001 57 39 071 00111001
10 A 012 00001010 26 1A 032 00011010 42 2A 052 00101010 58 3A 072 00111010
11 B 013 00001011 27 1B 033 00011011 43 2B 053 00101011 59 3B 073 00111011
12 C 014 00001100 28 1C 034 00011100 44 2C 054 00101100 60 3C 074 00111100
13 D 015 00001101 29 1D 035 00011101 45 2D 055 00101101 61 3D 075 00111101
14 E 016 00001110 30 1E 036 00011110 46 2E 056 00101110 62 3E 076 00111110
15 F 017 00001111 31 1F 037 00011111 47 2F 057 00101111 63 3F 077 00111111

Dec Hex Oct Bin Dec Hex Oct Bin Dec Hex Oct Bin Dec Hex Oct Bin
64 40 100 01000000 80 50 120 01010000 96 60 140 01100000 112 70 160 01110000
65 41 101 01000001 81 51 121 01010001 97 61 141 01100001 113 71 161 01110001
66 42 102 01000010 82 52 122 01010010 98 62 142 01100010 114 72 162 01110010
67 43 103 01000011 83 53 123 01010011 99 63 143 01100011 115 73 163 01110011
68 44 104 01000100 84 54 124 01010100 100 64 144 01100100 116 74 164 01110100
69 45 105 01000101 85 55 125 01010101 101 65 145 01100101 117 75 165 01110101
70 46 106 01000110 86 56 126 01010110 102 66 146 01100110 118 76 166 01110110
71 47 107 01000111 87 57 127 01010111 103 67 147 01100111 119 77 167 01110111
72 48 110 01001000 88 58 130 01011000 104 68 150 01101000 120 78 170 01111000
73 49 111 01001001 89 59 131 01011001 105 69 151 01101001 121 79 171 01111001
74 4A 112 01001010 90 5A 132 01011010 106 6A 152 01101010 122 7A 172 01111010
75 4B 113 01001011 91 5B 133 01011011 107 6B 153 01101011 123 7B 173 01111011
76 4C 114 01001100 92 5C 134 01011100 108 6C 154 01101100 124 7C 174 01111100
77 4D 115 01001101 93 5D 135 01011101 109 6D 155 01101101 125 7D 175 01111101
78 4E 116 01001110 94 5E 136 01011110 110 6E 156 01101110 126 7E 176 01111110
79 4F 117 01001111 95 5F 137 01011111 111 6F 157 01101111 127 7F 177 01111111

Dec Hex Oct Bin Dec Hex Oct Bin Dec Hex Oct Bin Dec Hex Oct Bin
128 80 200 10000000 144 90 220 10010000 160 A0 240 10100000 176 B0 260 10110000
129 81 201 10000001 145 91 221 10010001 161 A1 241 10100001 177 B1 261 10110001
130 82 202 10000010 146 92 222 10010010 162 A2 242 10100010 178 B2 262 10110010
131 83 203 10000011 147 93 223 10010011 163 A3 243 10100011 179 B3 263 10110011
132 84 204 10000100 148 94 224 10010100 164 A4 244 10100100 180 B4 264 10110100
133 85 205 10000101 149 95 225 10010101 165 A5 245 10100101 181 B5 265 10110101
134 86 206 10000110 150 96 226 10010110 166 A6 246 10100110 182 B6 266 10110110
135 87 207 10000111 151 97 227 10010111 167 A7 247 10100111 183 B7 267 10110111
136 88 210 10001000 152 98 230 10011000 168 A8 250 10101000 184 B8 270 10111000
137 89 211 10001001 153 99 231 10011001 169 A9 251 10101001 185 B9 271 10111001
138 8A 212 10001010 154 9A 232 10011010 170 AA 252 10101010 186 BA 272 10111010
139 8B 213 10001011 155 9B 233 10011011 171 AB 253 10101011 187 BB 273 10111011
140 8C 214 10001100 156 9C 234 10011100 172 AC 254 10101100 188 BC 274 10111100
141 8D 215 10001101 157 9D 235 10011101 173 AD 255 10101101 189 BD 275 10111101
142 8E 216 10001110 158 9E 236 10011110 174 AE 256 10101110 190 BE 276 10111110
143 8F 217 10001111 159 9F 237 10011111 175 AF 257 10101111 191 BF 277 10111111

Dec Hex Oct Bin Dec Hex Oct Bin Dec Hex Oct Bin Dec Hex Oct Bin
192 C0 300 11000000 208 D0 320 11010000 224 E0 340 11100000 240 F0 360 11110000
193 C1 301 11000001 209 D1 321 11010001 225 E1 341 11100001 241 F1 361 11110001

11
194 C2 302 11000010 210 D2 322 11010010 226 E2 342 11100010 242 F2 362 11110010
195 C3 303 11000011 211 D3 323 11010011 227 E3 343 11100011 243 F3 363 11110011
196 C4 304 11000100 212 D4 324 11010100 228 E4 344 11100100 244 F4 364 11110100
197 C5 305 11000101 213 D5 325 11010101 229 E5 345 11100101 245 F5 365 11110101
198 C6 306 11000110 214 D6 326 11010110 230 E6 346 11100110 246 F6 366 11110110
199 C7 307 11000111 215 D7 327 11010111 231 E7 347 11100111 247 F7 367 11110111
200 C8 310 11001000 216 D8 330 11011000 232 E8 350 11101000 248 F8 370 11111000
201 C9 311 11001001 217 D9 331 11011001 233 E9 351 11101001 249 F9 371 11111001
202 CA 312 11001010 218 DA 332 11011010 234 EA 352 11101010 250 FA 372 11111010
203 CB 313 11001011 219 DB 333 11011011 235 EB 353 11101011 251 FB 373 11111011
204 CC 314 11001100 220 DC 334 11011100 236 EC 354 11101100 252 FC 374 11111100
205 CD 315 11001101 221 DD 335 11011101 237 ED 355 11101101 253 FD 375 11111101
206 CE 316 11001110 222 DE 336 11011110 238 EE 356 11101110 254 FE 376 11111110
207 CF 317 11001111 223 DF 337 11011111 239 EF 357 11101111 255 FF 377 11111111

12
Tipos de Datos.

Tipos de datos fundamentales

• El tipo int es usado para representar valores enteros. El espacio de almacenamiento de int es
usualmente una palabra.
• El tipo char es usado para representar caracteres. El espacio de almacenamiento suministrado por
char es suficiente para almacenar un sólo carácter dentro de la implementación.
• El tipo float y double son usados para manejar números en punto flotante
• El tipo void es un tipo que indica que una función actúa como procedimiento.

Tipos adicionales y mecanismos de creación de tipos en C++.

• El tipo enum es un tipo el cual permite un número de constantes relacionadas a ser definidas.
• El tipo struct es un tipo definido que permite el agrupamiento de varias variables de algún tipo. Este
agrupamiento es también manejable siendo así permite a C++ manejar datos los cuales no se
ocupan completamente existe un tipo de dato - campos de bit.
• El tipo union es un tipo definido permite el agrupamiento de varias variables de algún tipo.
• El typedef puede ser usado para renombrar tipos.

Existen varios prefijos para tipos, el cual modifica el tipo

unsigned
Aplicado a int y char
signed
Aplicado a int y char
Este prefijo toma la interpretación de un entero signed, esto no es normalmente usado con int por
que por default es signed!
long
Aplicado a int
Este prefijo tomaría la cantidad de almacenamiento tan larga posible dentro de la implementación.
También este prefijo es solamente sustituible a un tipo de dato, es posible abreviar long int como
long. Esto es típicamente de 32 bits.
short
Aplicado a int
Este prefijo tomaría la cantidad más pequeña posible dentro de la implementación. Este prefijo
también es solamente sustituible para un tipo de dato, es posible abreviar short int como short.
const
Aplicado a todos los tipos
Variables con este prefijo deben y pueden ser solamente inicializados en tiempo de declaración.
Constantes tiene varios usos y la palabra clave const tiene varios significados dependiendo del
contexto.

13
Como asignar datos a una variable:

• Modificar tipos en una operación.


En una operación, si queremos que la respuesta sea de tipo DOUBLE, al menos uno de los numeros de
la división ha de ser de dicho tipo.

También se puede escribir asi.

14
Conversiones de tipos de datos.

• Conversión de INTDOUBLE.

• Conversión de STRING  INT.


Se emplea la función atoi(servar.cstr( ));
Declarar la librería:

Ejemplo:

• Conversión de INT  STRING.


Hacer uso de la función itoa de stdlib.h.
Ejemplo:

15
• Conversión de STRING  INTEGER.
o Empleamos la función atoi de la librería string.
o Atención, no usar punteros en el tipo de dato string.
o Ejemplo:
#include<iostream>
#include<string>

using namespace std;

int main () {
int integer;
string buffer = "123456789";
cout << "String:" << buffer << endl;
integer=atoi(buffer.c_str());
cout << "Integer:" << integer << endl;
return 0;
}

Conversión de CHAR a STRING.

16
Operaciones con tipos de datos diferentes.

Para los operadores +, -, *, /.

Int + int = double


int + double = double

17
2.1. int

Este tipo de datos es diseñado para almacenar valores numéricos enteros, y variables de este tipo son
inicializadas como sigue:

int a = 125;
int i = a + 1000;

El tamaño de almacenamiento de este tipo de datos varia de máquina a máquina, y es usualmente de 16 o


32 bits. Este tamaño de almacenamiento afecta los valores máximos que una variable de este tipo puede
almacenar.

Es interesante notar que el uso de este tipo de datos con los prefijos short y long no siempre tendrán un
efecto diferente. No existe nada que establezca que la versión short tenga un rango menor que long, pero el
long puede no tener un rango menor que short. Si el rango de valores los cuales son soportados por tu
implementación son importantes tú puedes usar los valores definidos en "limits.h" el cual tiene valores
#define para los límites de la capacidad de almacenamiento de todos los tipos estándar.

18
2.2.Uso de cadenas de caracteres

Las constantes de cadenas se colocan entre comillas. Ej.: “HOLA“.


Las constantes de caracteres char se colocan entre apostrofes. Ej.: ‘h ‘.

Ejemplos de cómo se puede usar un char

Uso de la clase string para manejar cadenas.

19
char
• Cada variable solo guardará un carácter.
• Este tipo de dato es diseñado para almacenar un sólo carácter, y puede ser inicializado en el momento
de la declaración como sigue:

char c = 'a';
char var('abcdefg');
char chVar[ 30 ] //Mriar arreglos.

• Las comillas sencillas indican que a es un carácter constante.


En muchas máquinas, el espacio de almacenamiento del tipo de dato char es de 8 bits, y es usualmente el
tipo de dato más pequeño. Mientras esto es más usado para almacenar caracteres simples, también es
posible representar valores numéricos con una variable tipo char.
Por ejemplo, las siguientes operaciones son legales:

char a = 'b', b = 3;
char c;

c = a + b;
cout << c << endl;

Esto produce la salida de e. Las operaciones sobre las variables antes de la proposición cout son
consideradas operaciones enteras. El operador cout sin embargo conoce que la variable c es de tipo char, y
por lo tanto su salida es un caracter. El valor numérico de c en este punto es 101, y puede ser convertida la
salida como sigue:

cout << (int) c << endl;

Un típico unsigned char de 8 bits puede entonces almacenar valores desde 0 hasta 255, y el signed char de
8 bits puede almacenar valores desde -128 a 127. Este char siempre tiene 256 (2^8) valores posibles.

El tipo de dato char es también utilizado en el almacenamiento de cadenas en C++.


Una string es una serie de caracteres consecutivos seguidos por un caracter nulo almacenados en un
arreglo.

20
2.3. float y double

Estos tipos son usados para representar números en punto flotante, y puede usar notación científica así
como la notación convencional fija.

Por ejemplo:

10E3 10e3 10e+5 51e-10 1.5 10.4e+5

Tiene que ser una constante en punto flotante, el número debe contener un punto decimal o un exponente.

Los tipos de datos double y long double pueden contener el mismo valor como un float, pero usa un
espacio de almacenamiento más largo, y puede por lo tanto tener valores con una precisión alta.

21
2.4. void

Este tipo de dato especial es usado en muchas ocasiones. Este no significa nada, y puede ser confundido
con NULL o 0 o cualquier valor ilegal.

El tipo void es a menudo usado en definición de funciones donde no existe un tipo de regreso, o la función
no toma argumentos. La omisión de void probablemente no causará que el programa falle al compilar, pero
puede producir una advertencia (warning) dado que el programa fuente no será "correcto".

void es a menudo utilizado en el contexto de apuntadores. Un apuntador void es usado de la misma forma
como cualquier otro apuntador, excepto que este debe ser convertido antes de que pueda ser usado. Por
ejemplo, para convertir un apuntador nulo a un apuntador entero usar:

(int *) the_void_pointer

22
2.5. enum Enumeraciones
Se emplea para nombrar constantes enteras pero sin usar la palabra const.
enum da un simple método para llevar a cabo esto en muchas circunstancias.
Por ejemplo, esto es usado a menudo para definir un número de valores el cual cualquier función dada
puede retornar.

Una forma de hacer esto sería definir cada uno de los valores a retornar como un nombre simbólico:

const int Success = 0;


const int Failure = 1;
const int InternalError = 2;

enum { Success=0, Failure=1,


InternalError=2 };

Otra forma de utilizar una enumeración:

enum ReturnType { Success, Failure, InternalError };

Esto ahora hace que del nombre de esta enumeración un tipo distinto. Ahora las variables de este tipo
pueden ser creadas:

ReturnType r = Success;

También es posible dar a cada uno de los valores enumeraciones, los cuales no necesitan ser
incrementados o positivos.

enum ReturnType { Success=10, Failure=2, InternalError=20 };

23
2.6. struct

Es algunas veces conveniente considerar una colección de variables como un sólo objeto. Supongamos que
queremos desarrollar un sistema de información para detalles personales, donde cada nombre de persona,
año de nacimiento y estatura son los detalles relevantes. En C++ podemos combinar estos detalles dentro de
una estructura.

La estructura de arriba podría ser definida como:

struct
{
char name[25];
int year;
float height;
} S;

Los miembros pueden ser accedidos como S.name, S.year y S.height. La definición anterior se hace de
manera equivalente a int i.

Podría ser muy tedioso tener que rescribir la definición de la estructura cada vez que una nueva variable
fuera necesaria, por lo tanto C++ permite el definir nombre a una estructura insertando una palabra entre
struct y la llave abierta.

struct person {
char name[25];
int year;
float height;
};

• Cuidado con el };
• No inicializar las variables dentro de la estructura.
• Si se puede inicializar una variable en el cuerpo del programa cuando se declara.
person jose = {10,5.5,1000};

Después de esta definición las variables pueden ser declaradas como sigue:

struct person p;
struct person people[50];

El especificardor typedef puede ser usando para definiciones cortas.

Una de las características únicas de structs es que pueden hacer uso de campos de bits de C++.

Realmente una clase y una estructura vienen a ser algo prácticamente igual.

24
Ejemplo:

25
Documentación sobre STRUCT.

Declaración de estructuras
§1 Sinopsis
Lo mismo que con el resto de las clases, el proceso de usar una estructura C++ comprende en
realidad tres pasos:
• definir la clase.
• Crear un objeto.
• Iniciar el objeto.

§2 Definir la clase
En contra de lo que ocurre con el resto de los tipos, que están pre-definidos en el lenguaje, por
ejemplo, al declarar char ch, ya se sabe exactamente que cosa es ch, en este caso hay que definir
previamente el tipo.

Los tipos estructura se declaran mediante la palabra clave struct. Sería algo así como:
struct Punto; // sentencia es una declaración incompleta.
struct Punt2 {int x; int y; int z; }; // Definición completa de una nueva clase tipo struct.

Tiene tres componentes perfectamente definidos (tres int: x, y, z respectivamente). Como puede
verse, los componentes se determinan de forma análoga a los parámetros de las funciones,
determinando tipo y nombre.
Es imprescindible el punto y coma ";" para separar los miembros (sin olvidar poner otro
después del último).

§2.1 En C++ las estructuras son un tipo de clases; si nos referimos a la terminología de la POO
diríamos que en esta fase estamos definiendo la clase. El conjunto de declaraciones dentro de los
corchetes {...; ...; ...; } declara los nombres y tipos de sus miembros. Los miembros pueden ser de
cualquier tipo con una excepción:
• §2.2 Un miembro no puede ser la estructura que se declara porque daría lugar a una declaración
circular (lo definido está dentro de su definición). Ejemplo:

struct mystr { mystr s }; // Ilegal

• §2.3 Uno, o varios, de los miembros puede ser un puntero a la estructura que se está declarando.
Ejemplo:
struct mystr { mystr *ps } // Ok: Correcto

Nota: esta interesantísima posibilidad constituye la base de estructuras auto referenciadas; una
técnica de programación que tiene amplias posibilidades de aplicación. Por ejemplo, listas enlazadas
y árboles.

• §2.4 También es posible que los miembros de una estructura sean a su vez estructuras
previamente definidas, dando lugar a estructuras anidadas. Por ejemplo:

struct Punto
{
int x; int y;
};
struct Linea
{
struct Punto p1;
struct Punto p2;
} c1;
26
Declara Linea como un tipo struct con dos miembros, cada uno de los cuales es un tipo struct Punto.
Nota:
• En C las funciones no pueden ser miembros de la estructuras C (de lo contrario serían clases). En
cambio, sí están admitidos los "punteros a función devolviendo..." (ya que son variables, no
métodos).
• Las estructuras C++ sí pueden incluir funciones miembro (de hecho son clases), además, en C++
la palabra struct puede omitirse.
• Es importante tener en cuenta que, en este punto (definición), solo está permitido señalar tipo y
nombre de los miembros, sin que se pueda efectuar ninguna asignación; ni aún en el caso de que
se trate de una constante.
Por ejemplo, las definiciones que siguen serían ilegales, pues todas implican una asignación en la
definición del segundo miembro:

struct Str {int x; int y = 2; }; // Error!


struct Str {int x; const int y = 3; }; // Error!
struct Str {int x; char c = 'X'; }; // Error!
struct Str {int x; char * st = "Hola"; }; // Error!
struct Str {int x; "Hola"; }; // Error!
struct Str {int x; int a[2] = {3, 4};}; // Error!

§3 Crear un objeto (instanciar la clase)


Un segundo paso es declarar una variable como perteneciente al nuevo tipo. Del mismo modo que
para declarar una variable ch como de tipo char declarábamos: char ch;, en este caso, para declarar
una variable st como estructura tipo punto se utiliza:

struct Punto pt; // C y C++

En C++ no es necesario señalar que Punto es una estructura (suponemos que ya lo sabe el
compilador por las sentencias anteriores), de forma que si no existe ninguna otra variable punto en el
mismo ámbito de nombres, no hay ambigüedad y se puede poner directamente:

Punto pt; // C++

Usando la terminología de la POO diríamos que estamos instanciando la clase, es decir, creando un
objeto concreto pt, con espacio en memoria, que pertenece a (es derivado de) dicha clase. Dichos
objetos sí pueden ser asignados con valores concretos en sus miembros.
§3.1 Advertir que cada declaración de (tipo de) estructura introduce un nuevo tipo, distinto de
los demás (una nueva clase), de forma que las declaraciones:

struct StA
{
int i,j;
} a, a1;
struct StB
{
int i,j;
} b;

Definen dos tipos de estructura distintas: StA y StB; los objetos a y b1 son del tipo StA, pero a y b
son de tipo distinto.

27
Desde la óptica de la POO la frase anterior se enunciaría como sigue: "definen dos clases distintas,
StA y StB; los objetos a y b1 son instancias de StA, pero b lo es de la clase StB. Por tanto, a y b son
objetos de tipo distinto.

§3.2 De la misma forma que ocurre con el resto de variables, puede declararse más de un elemento
en la misma sentencia:
struct Punto p1, p2, p3,... pn;
Sin embargo, de una variable de tipo estructura no es posible derivar nuevas variables, es decir no es
lícita la sentencia que sigue (utilizando la terminología de C++ lo enunciaríamos diciendo: de un
objeto no puede instanciarse otro objeto).

struct p1, p11, p12, p13,... p1n; // NO!!

§4 Iniciar el objeto.
Un tercer paso es inicializar dicha variable. Del mismo modo que para iniciar ch se realizaba una
asignación del tipo: ch = 'x', en este caso se utiliza la asignación (análoga a la de matrices):

st = { 12, 25, 3};

Los pasos 2 y 3 se pueden realizar en la misma sentencia. Por ejemplo:

struct punto st = { 12, 25, 3};

También puede realizarse los tres pasos en una misma sentencia:

struct punto { int x; int y; int z; } p1 = { 12, 25, 3};

Una vez definido el nuevo tipo, pueden declararse punteros y matrices de estructuras de dicho tipo.
Por ejemplo:

struct stA { ... }; // define la estructura tipo stA


struct stA st, *pst, arst[10];

La segunda línea declara que st es una estructura de tipo stA; que pst es un puntero a dicho tipo, y
que arst es un array de 10 estructuras tipo stA.

§4.1 Es posible incluso declarar estructuras sin asignar un nombre al tipo correspondiente. Por
ejemplo:

struct { ... } st, *pst, arst[10];

§5 Espacio de nombres de estructuras.


Los nombres de tipos de estructura comparten el espacio de nombres con las uniones y
enumeraciones (las enumeraciones dentro de una estructura están en un espacio de nombres
diferente). Ver L.4 y L.11 en el ejemplo de abajo.
Los nombres de estructura están en un espacio de nombres diferente que el de nombres de tipos de
estructura y nombres de etiqueta (en C++ solo si no tienen un constructor). Ver L.8 y L.18 del
ejemplo de abajo.

Los miembros de estructuras disponen de un espacio de nombres cerrado y particular (espacio de


nombres de miembros de clases), de forma que sus nombres se pueden repetir con los de miembros
de otras estructuras o con los de otros espacios (ver L.6, L.7, L.12 y L.16 del ejemplo ).
La consecuencia es que dentro del mismo ámbito, los nombres de estructuras y uniones deben ser
únicos (ambos comparten el espacio de nombres de clases), aunque no hay inconveniente que
28
compartan los nombres con los miembros de los otros tres espacios: El de etiquetas; el de miembros
(de clases) y el de enumeraciones [3]. ( 4.1.11 Espacion de Nombres y 4.11.4 Ambito de
nombres de clase).
§5.1 Ejemplo
goto s;
...
s: // L.3 Etiqueta
struct s { // L.4 OK: nombres de tipo_de_estructura y etiqueta en
// espacios diferentes
int s; // L.6 OK: nombres miembro de estructura en espacio privado
float s; // L.7 ILEGAL: nombre de miembro duplicado
} s; // L.8 OK: nombre_de_estructura en espacio diferente de
// nombre de etiqueta (L.3) y de tipo_de_estructura (L4)
// En C++, esto solo es posible si s no tiene un constructor
union s { // L.11 ILEGAL: nombre duplicado con el de tipo s (L.4)
int s; // L.12 OK: nuevo espacio de miembros
float f;
} f; // L.14 OK: espacio diferente que el de miembros (ver L.8)
struct t {
int s; // L.16 OK: nuevo espacio de miembros
...
} s; // L.18 ILEGAL: nombre duplicado con el de estructura s (L8)

§6 Declaraciones incompletas
Las declaraciones incompletas, conocidas también como declaraciones anticipadas o adelantadas;
consisten en que un puntero a una estructura tipoA puede aparecer en la declaración de otra, tipoB
antes que tipoA haya sido declarada. Ejemplo:

struct A; // declaración anticipada


struct B { struct A *pa };
struct A { struct B *pb };

En este caso, la primera declaración de A se denomina incompleta o anticipada, porque no existe


definición para ella (cuales son sus miembros). Este tipo de declaración sería correcta aquí, porque
en la declaración de B no se necesita conocer el tamaño de A (solo el de un puntero a estructura).

29
§7 Hay que advertir que en C++ es muy frecuente utilizar typedefs en la declaración de estructuras.
De hecho, los ficheros de cabecera de los compiladores C++ están repletos de ellos. Es muy
frecuente que utilicen expresiones como:

typedef struct {
unsigned char *curp; // Current active pointer
unsigned char *buffer; // Data transfer buffer
int level; // fill/empty level of buffer
int bsize; // Buffer size
unsigned short istemp; // Temporary file indicator
unsigned short flags; // File status flags
wchar_t hold; // Ungetc char if no buffer
char fd; // File descriptor
unsigned char token; // Used for validity checking
} FILE; // This is the FILE object
Por tanto, es posible escribir sentencias como:
#include <stdio.h>

int main(void) {
FILE *in, *out; // define punteros a estructuras FILE
...
Sin embargo, dentro del mismo ámbito de nombres, C++ no permite que una estructura (o clase)
tenga el mismo nombre que un typedef declarado para definir un tipo diferente. Ejemplo:

typedef void (*C)();


...
class C { // Error declaración múltiple para C.
...
};

§8 Tipos anónimos
El nombre de un tipo de estructura puede omitirse, teniéndose lo que se llama un tipo anónimo (sin
nombre). Pueden utilizarse en declaraciones de componentes separados por comas cuando se quiere
indicar que los componentes son (o derivan de) un tipo de estructura determinado. Presenta el
problema de que al no poderse referir más al tipo (por no tener nombre), no pueden declararse más
objetos adicionales en ningún otro sitio. Ejemplo:

struct { ..; ..; ..; } s, *ps, arrs[10]; // tipo sin nombre

Es posible crear un typedef al mismo tiempo que se declara una estructura, con o sin nombre, como
se ve en los ejemplos. Generalmente no se necesitan un typedef y un nombre al mismo tiempo, ya
que cualquiera de ellos sirve para las declaraciones.

typedef struct mystruct { ..;..; } MST;


MST s, *ps, arrs[10]; // igual que struct mystruct s, etc.
typedef struct { ..; ..; } YST; // sin nombre
YST y, *yp, arry[20];

Cuando son miembros de clases, las estructuras y uniones anónimas son ignoradas durante la
inicialización.
Nota: el ANSI C++ solamente permite estructuras anónimas que declaren un objeto. Por su parte, el
ANSI C no permite estructuras anónimas, y el compilador C++ de Borland permite varios tipos de
estructuras anónimas que extienden el estándar ANSI.

30
§8.1 Debido a que no hay propiedades de instancia, la sintaxis C++ para las estructuras anónimas no
permite referenciar un puntero this. Por consiguiente, mientras que una estructura C++ puede tener
funciones miembro, las estructuras anónimas C++ no pueden tenerlas.
Los miembros de las estructuras anónimas pueden ser accedidos directamente en el ámbito en que
las estructuras han sido declaradas sin la necesidad de utilizar la sintaxis x.y o p->y. Por ejemplo:

struct my_struct {
int x;
struct {
int i;
};
inline int func1(int y) { return y + i + x; }
} S;

int main() {
S.x = 6; S.i = 4;
int y = S.func1(3);
printf(“y is %d“, y);
return 0;
}

§8.2 Estructuras anónimas anidadas


Borland C++ permite estructuras anónimas y que no sean usadas para declarar un objeto o cualquier
otro tipo. Tienen la forma que se indica:
struct { lista-de-miembros };

Las estructuras anónimas pueden ser anidadas, es decir, declaradas dentro de otra estructura, unión o
clase. En estos casos, la estructura externa debe tener nombre. Por ejemplo:

struct my_struct {
int x;
struct { // estructura anónima anidada dentro de my_struct
int i;
};
inline int func1(int y);
} S;

Para compatibilidad con el compilador Visual C++ de Microsoft, el compilador Borland C++
permite declarar una estructura con nombre que no declara ningún objeto. Estas estructuras
huérfanas deben ser anidadas. Por ejemplo:

struct Direccion {
char calle[25];
int numero;
};

struct Persona {
char nombre[35]
struct Direccion; // estructura huérfana
} candidato; // una instancia de Persona

candidato.numero = 10;

31
2.7. Const

Este operador tiene diferentes efectos, pero es usado para especificar cuando las variables permacen
constantes.

const int a;

argumentos constantes de una función - void function(const int& a)

Variables Constantes
Si una declaración de variable esta precedida por la palabra const , esta se convierte en constante. Su valor
no cambiará dentro de su alcance, y esto significa que no soporta un asignamiento.
Su valor tiene que ser asignado cuando es declarado. Por ejemplo:

const int Max = 100;

Si un número de constantes necesitan ser declaradas posteriormente, entonces un método alternativo, existe
enum.

Apuntadores constantes
Cuando una declaración const es realizada de un apuntador a un objeto, esto hace constante al objeto, no el
apuntador. Por ejemplo:
const char *pt = "The cat sat on the mat.";
Para este ejemplo, podría ser técnicamente posible cambiar el apuntador pt a otro valor proporcionando la
misma cadena establecida en esta localidad. Sin embargo, siempre se puede decir que el apuntador pt
siempre apuntará a la misma área de memoria. Para hacer que el apuntador apunte a una constante:
char *const pt = "The cat sat on the mat.";
Para este ejemplo, podría no ser posible cambiar el apuntador y por ejemplo una línea sugestva pt=0 podría
ser invalidada. Sin embargo, podría ser posible cambiar la cadena la cual es apuntada por pt. También es
posible hacer al apuntador y al objeto constantes especificándolos ara que sean constantes.
const char *const pt = "The cat sat on the mat.";
Usando constantes en una función
Es posible declarar a los argumentos de una función como const cuando son declarados o definidos. Por
ejemplo:
char *strcpy(char *dest, const char *src);
Esto significa que a la función strcpy() no le esta permitido alterar la cadena apuntada por src.

32
2.8. typedef

La palabra typedef es proporcionada para permitir un nuevo nombre de tipo a ser especificado.
• No es un tipo nuevo.
• Solo es un alias de un tipo.

Su sintaxis es :

typedef <type> <name>;

Por ejemplo :
typedef int number; // number se refiere a un entero!

typedef char* string; // string se refiere a un apuntador a un char.

typedef struct { int x; int y; } location;


// location se refiere a un par x,y de enteros.

typedef union { char *studentid; char *graduateid; } uni_id


// uni_id es identificador de un graduado o estudiante.

33
BOOL.

False = 0
True = Cualquier valor diferente a 0.
Lo normal es procurar que sea 1.

34
3. Apuntadores

Los apuntadores en C++ son usados por varias razones. La más común es para permitir la asignación de
memoria dinámica.
También proporcionan un mecanismo para pasar la dirección de los objetos a las funciones, aunque esto
también puede ser realizado usando el método de pass-by-reference de C++.

En C++, un apuntador es actualmente una variable la cual es usada para almacenar localidades de memoria.
Una declaración apuntador puede incluir el tipo del dato al que apunta.

Por ejemplo, la siguiente declaración especifica la variable pt la cual mantendrá la dirección de memoria de
un objeto de tipo int.

int *pt;

Notar que esto no asigna actualmente ningún espacio de almacenamiento para un entero. Para asignar y
liberar memoria, los operadores new y delete pueden ser usados.(Mirar variables dinámicas).

Un objeto puede tener espacio asignado a una cierta dirección y la dirección de la memoria puede ser usada
para acceder a ello. Los apuntadores son usados para almacenar esas direcciones de memoria por lo tanto
los programadores pueden acceder a ello.

Using pointers
Los apuntadores son declarados en la misma forma que las variables normales: el valor que ellos almacenan
es una dirección de memoria. Una de las ventajas de esto es que permiten la asignación de memoria
dinámica, y son desde aquí usados en definiciones más complicadas que almacenan estructuras tales como
listas ligadas.

El siguiente segmento de código de ejemplo muestra como puede ser usado un apuntador:

int *pt;
int no = 5;

pt = &no;

cout << *pt << endl;


no = 10;
cout << *pt << endl;

cout << pt << endl; //Esta línea me permite ver la direccion del apuntador //dentro de la
memoria

pt es declarado como un apuntador a un entero usando el operador de dirección &.


no es declarado como un entero e inicilizado a 5.
A pt se le asigna la dirección de no.
La siguiente declaración utiliza el operador de referencia (``*'') para acceder al contenido de la dirección de
memoria apuntada por pt.
Este segmento de código producirá la salida:
5
10
Es algunas veces deseable tener alguna forma de decir si un apuntador ha sido determinado o no. A menudo
es puesto el apuntador a 0 ( o el valor null ) debido a esto es siempre una dirección de memoria inválida.

35
Muy importante:

* este simbolo recibe el nombre de Operador de Desferenciación.


& este símbolo recibe el nombre de Operador dirección.
Cuando se llama un apuntador:
• Si SI ponemos el *, nos da el valor que hay en ese hueco de memoria.
• Si NO ponmos el *, nos da la dirección de esa memoria.
Int variable;
Int *apuntador;

Referenciar un apuntador a una variable.


No se pone el *.
Sintaxis:

Apuntador = &variable. No se pone el *.

36
Ejemplo de apuntadores:

Este ejemplo muestra:


• el valor de los punteros.
• La dirección a la que apuntan en memoria.

37
38
Apuntadores a cadenas

En C++ una cadena esta definida como un arreglo de caracteres donde el último elemento del arreglo es el
carácter nulo. Se proporciona una forma sencilla para inicializar cadenas: mejor que inicializar cada elemento
individualmente, como se hace en arreglos normales, la cadena completa puede ser encerrada en comillas
dobles. Lo siguiente define a pt como un apuntador a un arreglo de caracteres e inicializa los elementos del
arreglo para contener la cadena "El mundo es rosa" seguida por el carácter nulo.

char *pt = "The world is pink";

El carácter null es necesario para que las rutinas que manipulan varias cadenas conozcan que tan grande
son las cadenas. Para imprimir esta cadena la siguiente línea puede ser usada:

cout << pt << endl;

Lo cual produce la salida:

El mundo es rosa

39
Apuntadores NULL

Cuando los apuntadores son usados en programas de C++, es muy importante que ellos siempre apunten a
un área de memoria asignada. Si ellos están apuntando a un área de memoria no asignada y son
desreferenciados, entonces esto causará un error fatal en el programa. O al menos tendrá efectos
inesperados.

Se garantiza al programador que un apuntador el cual ha sido asignado con un llamado a new, o apunta a
una variable la cual ha sido asignada, nunca será cero, o NULL. Este hecho es utilizado a menudo para
examinar la validez de apuntadores.

Por ejemplo, si una funció Find() es escrita como sigue,

char *Find(int i); // Encuentra un nombre dado por número

Esta función puede regresar una cadena conteniendo un nombre. Sin embargo, esto no proporciona un
mecanismo para manejar cualquier falla al encontrar un nombre dentro de la función. Una posible solución
podría ser regresar una cadena tal como "Falla", pero esto entonces significa que se tiene que realizar más
trabajo para discernir un nombre de la respuesta Falla.

Por lo tanto, la respuesta usual es realizar una función que retorne null en un apuntador cuando esta falle.
Esto entonces permite al apuntador ser regresado por la función para ser revisado como sigue:

char *name;
name = Find(100); // Encuentra al usuario 100

if ( !name ) // El nombre no existe


cout << "El usuario no existe " << endl;
else
cout << "El nombre del usuario es " << name << endl;

La evaluación revisa el valor ! name del valor name. La operación ! puede ser vista como si name es null

Muchas de las funciones de librería estándar de C usan esta clase de mecanismo para regresar una
respuesta satisfactoria o un error.

40
Punteros a estructuras.

Los punteros también pueden apuntar a estructuras. En este caso, para referirse a cada elemento de la
estructura se usa el operador (->), en lugar del (.).
Ejemplo:

41
Variables dinámicas con punteros - Memoria dinámica.

Cuando se ejecuta un programa, el sistema operativo reserva una zona de memoria para el código o
instrucciones del programa y otra para las variables que se usan durante la ejecución. A menudo
estas zonas son la misma zona, es lo que se llama memoria local.
También hay otras zonas de memoria, como la pila, que se usa, entre otras cosas, para intercambiar
datos entre funciones.
El resto, la memoria que no se usa por ningún programa es lo que se conoce como "heap" o montón.
Cuando nuestro programa use memoria dinámica, normalmente usará memoria del montón, y no se
llama así porque sea de peor calidad, sino porque suele haber realmente un montón de memoria de
este tipo.
C++ dispone de dos operadores para acceder a la memoria dinámica, son "new" y "delete". En C
estas acciones se realizan mediante funciones de la librería estándar "stdio.h".

Hay una regla de oro cuando se usa memoria dinámica:


T oda la memoria que se reserve durante el programa hay que liberarla antes de salir del
programa.
No seguir esta regla es una actitud muy irresponsable, y en la mayor parte de los casos tiene
consecuencias desastrosas. No os fiéis de lo que diga el compilador, de que estas variables se liberan
solas al terminar el programa, no siempre es verdad.
• Y mucho cuidado: si pierdes un puntero a una variable reservada dinámicamente, no podrás
liberarla.
Ejemplo:

42
43
El operador new

El operador new da un método de asignación de memoria dinámica. Esta regresa la dirección de la memoria
asignada y puede ser usado para asignar memoria para cualquier tipo de dato. Para hacer uso de la
memoria asignada es usual declarar un apuntador para almacenar la dirección de esta.

Ejemplo
int *ipt;
ipt = new int;
delete ipt; //borro la variable dinámica.
La memoria necesita almacenar un entero, pueden entonces ser asignada usando new, y el apuntador ipt
puesto a apuntar a esta memoria.
El operador de referencia puede ser usado para acceder a la memoria asignada ( es decir *ipt = 5
almacenará el valor 5 en la memoria asignada)

Esta memoria permanecerá asignada hasta que el programa termine, o hasta que la memoria sea liberada
usando el operador delete.

Asignación de arreglos

También es posible crear arreglos dinámicamente en esta forma. Si se desea un arreglo de 20 enteros,
entonces se crea como sigue. Un apuntador es usado para almacenar la localidad del primer entero en el
arreglo, y el espacio para 20 enteros es asignado en un bloque contiguo:

int *array;

array = new int[20];

Cada uno de los elementos del arreglo puede ahora ser accesado mediante el apuntador. Por ejemplo, el
elemento 15 puede ser accesado como sigue.

array[14] = 10;
cout << array[14] << endl;

Este método para la asignación de arreglos es más complicado que el método estático usual, pero esto
significa que el tamaño del arreglo puede ser asignado durante la ejecución del programa y no en el código
fuente.

Notar que cuando se utiliza new para asignar espacio para un arreglo multidimensional, sólo una de estas
dimensiones puede ser una variable: las otras deben ser valores constantes.

Existen muchas estructuras de datos las cuales confían en esta habilidad para asignar y desasignar memoria
dinámicamente, tales como las listas ligadas.

44
El operador delete

Este operador es usado para liberar memoria la cual ha sido asignada por el operador new. La memoria que
ha sido asignada con el operador new se recupera hasta que el programa termina, o hasta desasignarla de
esta manera. Esto significa que para programas grandes, la memoria será malgastada si esta no es borrada.

Si un objeto ha sido asignado de la siguiente manera,

int *ipt;
ipt = new int;

Entonces este puede ser borrado usando la siguiente línea.

delete ipt;

Es importante que el apuntador (en este caso ipt) este apuntando a una localidad de memoria la cual ha sido
asignada con el operador new. Si esto no es así el resultado está indefinido!

Este mismo método es usado para desasignar memoria si este es un tipo de dato básico o un objeto
complejo. El único método diferente usado es cuando un arreglo necesita ser desasignado.

Desasignación de arreglos

Si un arreglo, en este caso un arreglo de enteros, ha sido asignado de la siguiente manera:

int *array;

array = new int[10];

entonces este es desasignado como sigue:

delete [] array;

El [] sirve para mostrar que un arreglo podrí ser desasignado, no un sólo dato objeto.

45
4. Variables

::var Variables locales y globales con el mismo nombre

Cuando una variable local y una global tienen el mismo nombre, prevalecerá la local a no ser que a la
variable se la interponga el sufijo ::.

#include <iostream>
using namespace std;

int var1=1;

int main()
{
int var1=2;

cout<<var1<<endl; //Llamada a variable local

cout<<::var1<<endl; //Llamada a variable global

return 0;
}

46
Declaraciones

Declaración de variables.

Antes de que una variable pueda ser usada en una función de C++, esta tiene que ser declarada. La forma
de declarar una variable es:-

<Tipo de dato> <Nombre de la variable>;

Notar que la declaración es finalizada con un punto y coma.


Las Variables en C++ pueden consistir de letras, dígitos, o guiones bajos y son sensitivos al caso. Sin
embargo, el primer carácter debe ser una letra o un guión bajo. Los siguientes son ejemplos de variables
declaradas en esta forma.
char c;
int no;
char *pt;
long int lno;

Es importante notar que mientras es válido usar guiones bajos al principio del nombre de un identificador, no
es recomendable debido a que existen convenciones usadas por los compiladores. También es
recomendable limitar la longitud máxima de los nombres de las variables debido a que algunos compiladores
sólo utilizan una parte truncada del nombre.

Diferentes variables del mismo tipo pueden ser declaradas en una proposición. Por ejemplo:

char a, b, c;
int x, y, z;

Aquí, a, b y c son declaradas de tipo char, y x, y, z de tipo int.

También es posible inicializar variables cuando estas son declaradas. Por ejemplo:-

char c = 'a';
int no = 1;

Cuando una variable es declarada esta tiene un alcance asociado. Esto está determinado por el método
usado para declarar la variable. Las variables pueden tener un alcance local o global. Es una buena práctica
limitar el alcance de las variables lo más posible para dar mantenimiento al código. Es conveniente que tú
comprendas el concepto de alcance de una variable antes de declarar y utilizar variables.

Declaración de funciones

Para acceder a funciones las cuales no están contenidas dentro del código en el archivo fuente, es necesario
declararlas. Por ejemplo:

extern void foo(void);

Esta declaración dice al compilador que existe una función foo(), y que esta está definida en otro archivo
fuente. El tipo regresado por esta función será void y no acepta argumentos. El extern no es necesario pero
puede ayudar a la lectura de programas.

Es importante que los programadores estén enterados que una declaración es completamente diferente de
una definición. Una definición (la función actual) es usada para asignar memoria a la función, donde la
función sólo permite al compilador saber que la función dada será definida en otra parte. Una sola función
puede tener múltiples declaraciones, pero sólo una definición.

Nota: Las declaraciones de variables son también definiciones a menos que la palabra extern sea usada.
Por ejemplo - las declaraciones anteriores de esta página son también definiciones.

47
Arreglos , Arrays o Matrices

Arreglos simples
Los arreglos en C++ permiten números grandes de tipos de datos simples para ser representados
fácilmente. Cambiar el nombre individual de un número grande de variables simples, es posible
definiendo un arreglo de ellos, y accesar los elementos individuales por sus posiciones en el arreglo.
Por ejemplo:
int a,b,c,d,e;

Este cambio puede ser representado por un arreglo de 5 enteros, declarados como:
int i[5];

• Cada uno de los elementos en este arreglo puede entonces ser accedidos usando su índice. Por
ejemplo haciendo i[3] = 5; asignará el valor 5 al elemento 4 del arreglo
• Notar que el índice para los arreglos en C++ comienzan en 0.
Para el arreglo de 5 elementos, el índice corre desde 0 a 4.
• Una declaración de un arreglo consiste de un tipo de dato, un identificador, y un tamaño.
<tipo de dato> <identificador> [ tamaño ];
• No está permitido usar variables para indicar el tamaño de un array.
Int array[x];  NO permitido!!

El tamaño debe ser una constante la cual puede ser evaluada en el tiempo de compilación. No es
posible crear un arreglo usando una variable de esta forma. (Para hacerlo se requiere del uso del
operador new)

Inicializando arreglos

Es posible inicializar explícitamente un arreglo en la siguiente forma:

double n[4] = { 0.4, 1.7, 6.2, 5.4 };


char var[5];

ejemplos:

48
Nota

No existe ninguna revisión para ver si el programa esta intentando acceder un índice el cual esta fuera de los
límites del arreglo. Del ejemplo anterior n[7] = 0.6 podría causar resultados impredecibles cuando el
programa sea ejecutado: esto podría llegar a sobrescribir algunos otros datos que estén siendo usado por el
programa, o causar una falla de segmento o error del bus.

Arreglos multidimensionales

Un arreglo de dimensión simple puede ser definido como:

int i[5];

Esto crea un bloque de 5 enteros el cual puede ser visto como:

0 1 2 3 4

Un arreglo bidimensional puede ser visto entonces como:

0 1 2 3 4
5 6 7 8 9
10 11 12 13 14

Esto puede ser definido como:

int i[3][5];

La primera dimensión se refiere al número de renglón y la segunda al número de columna. Para ser
referencia al elemento 8 ) en este arreglo bidimensional, i[1][3] podría ser usado. Un ejemplo del uso de un
arreglo bidimensional puede ser guardar las calificaciones de todos los exámenes que un grupo de alumnos
realizó: cada columna corresponde a un estudiante, y cada renglón corresponde a un examen. Es posible
encontrar la calificación que el estudiante 2 obtuvo en el examen 7 accesando i[2][7].

Esto puede ser extendido para tener cuantas dimensiones sean requeridas insertando más []'s

Inicialización
Como en un arreglo simple, es posible inicializar un arreglo multidimensional en la declaración. Por ejemplo:
int i[3][2] =
{
{ 0, 1 },
{ 2, 3 },
{ 4, 5 }
};

La anidación de las llaves es opcional, y el ejemplo anterior pueder ser escrito como sigue, aunque esto es menos claro:

int i[3][2] = { 0, 1, 2, 3, 4, 5 };

49
0
0
0

Pasando arreglos a funciones

En C++, los arreglos nunca son pasados por valor. En cambio un apuntador al primer elemento en el
arreglo es pasado. Esto permite a la llamada de la función accesar el dato en el arreglo, sin tener que copiar
y pasar el arreglo entero a la función. Sin embargo, esto significa que si la función altera los valores de
cualquiera de los elementos, esto afecta el dato original.

Una función la cual acepta un arreglo unidimensional como un argumento puede ser declarado como sigue:

void Function( int [] );


void Function( int * );

C++ interpreta a int[] como un apuntador al primer elemento, como lo hace con int *. No existe ninguna
necesidad de especificar el tamaño del arreglo que es pasado, lo cual significa que la misma función puede
aceptar arreglos de cualquier tamaño, pero también significa que la función no conoce que tan grande es el
arreglo.

Un arreglo multidimensional declarado como un argumento formal a una función debe especificar el tamaño
de todas sus dimensiones. Por ejemplo una función la cual toma un arreglo de 4 por 5 por 8 enteros y no
regresa nada puede ser declarada como lo siguiente:

void Function( int [4][5][8] );


void Function( int [][5][8] );

Notar que la segunda forma puede ser pasar un arreglo con cualquier número de elementos en la primera
dimensión

50
Vector – Array
• Se encuentra en la librería #include<vector>.
• Vector es una plantilla definida en el espacio std y declarada en el fichero de cabecera <vector> que
facilita la creación y manipulación de matrices.
• Es otra manera de crear y usar matrices.

• Para definir una matriz de una dimensión, su sintaxis es la siguiente:

vector <tipo> nombre(tamaño,[val]);

tipo  Tipo de los elementos de la matriz.


Nombre  Nombre que le damos a la matriz.
Tamaño  Numero de elementos que tendrá la matriz
Val  es opcional, será utilizado para iniciar los elementos de la matriz.

Iteradotes.
Son funciones que se utilizan para navegar a través del array al igual que si este fuera una base de
datos.

MIRAR TUTORIAL: TutorialEdy3-librerias

También está la Librería <Map> para las matrices asociativas.

51
Goto

Sintaxis:

etiqueta:

Llamada para salto a etiqueta:


goto etiqueta;

• No olvidar los “ : “ detrás de la etiqueta.

Ejemplo:

52
6. Proposiciones

53
54
Proposiciones condicionales

Las Proposiciones condicionales en C++:

• La proposición if.
• La proposición switch.

55
If – else

• El compilador siempre aparea el else con el if más cercano a él.


• Si en un if, o un else o un elseif, hay más de una función en su cuerpo, entonces estas se pondrán entre
{ }.
• Puede emplearse break para salir de un ciclo antes de lo deseado.

if (condición)
...;

if (condición)
...;
else
...;

if (condición 1)
{
If (condicion 2)
... ;
else (condición 3)
....;
}
else
...;

if (condición)
…;
else if (condición 2)
…;
else if (condición 3)
…;
else
…;

56
Ejemplo
#include <iostream.h>
int main()
{
int numero(10),ticke;
cout<<"El numero por el que va la cola es el 10\n"
<<"Cual es tu ticke? ";
cin >>ticke;
if (ticke<numero)
cout<<"\n\nTienes que esperar.\n";

else if (ticke == numero)


cout<<"\n\nEs tu turno!\n";

else
cout<<"\n\nLo siento pero se ha pasado su turno\n";
return 0;
}

• Ejemplo de if, else if, else.

main()
{
int var1;
var1=10;

if(var1<10)
{
cout<<"var1 es MENOR que 10.\n";
}
else if(var1>10)
{
cout<<"var1 es MAYOR que 10.\n";
}
else
{
cout<<"var1 = 10.\n";
}

return 0;
}

57
switch

La proposición switch puede a menudo ser usada como un reemplazo para anidaciones profundas de las
proposiciones if-else. La forma usual de una proposición switch es la siguiente.

switch ( <expresión> )
{
case <valor1>:
...
break;

case <valor2>:
...
break;

default:
...
break; Opcional
}

La variable es evaluada y comparada con cada uno de los valores. Si uno de estos valores es igual,
entonces el bloque de proposiciones que va después de la proposición case es evaluado, hasta el break. Si
ninguno de los valores es igual a la variable, entonces el caso default es utilizado.

Nota:
Una proposición break debe ser especificada para finalizar la evaluación de la proposición switch. Si esta no
es encontrada, entonces el resto de las proposiciones en la proposición switch son evaluadas.

Por ejemplo:

58
7. Proposiciones iterativas

Las Proposiciones iterativas en C++:

• La proposición for.
• La proposición while.
• La proposición do.
• Puede emplearse break para salir de un ciclo antes de lo deseado.

59
7.1 for

El ciclo for es más usado cuando un bloque de proposiciones necesitan ser evaluadas un número de veces.

for ( <inicial>; <expresión condicional>; <modificadores> ) <proposición>

inicial
Las expresiones aquí son evaluadas desde el comienzo de la ejecución del ciclo del for. Esto es
normalmente usado para incializar variables las cuales están basadas en el ciclo.

expresión condicional
Esto es evaluado al comienzo de cada iteración. Si esta es falsa, entonces el ciclo es terminado.

modificadores
Las proposiciones aquí son evaluadas al final de cada iteración. Esto es usualmente usado para
modificar variables las cuales han sido inicializadas en la sección inicial del ciclo del for.

• Puede emplearse break para salir de un ciclo antes de lo deseado.

Ejemplos

60
7.2 La proposición while

La proposición while es usada para ejecutar una proposición, o un bloque de proposiciones, mientras el
resultado de evaluar una condición sea verdadero.

• Puede emplearse break para salir de un ciclo antes de lo deseado.

En C++, una proposición while toma la forma:

while ( expresión condicional )


proposición

while ( expresión condicional )


{
proposición
proposición
...
}

La expresión condicional es evaluada al comienzo de cada ciclo. Cuando esto primero se evalua a cero, el
ciclo está terminado. La proposición iterativa relacionada do asegura que un ciclo while es ejecutado al
menos una vez.

Ejemplos
while ( a < 10 ) ...

while ( ! node.Empty() ) ...

7.3 La proposición do

La proposición do es usada para formar un ciclo el cual ejecuta un bloque de proposiciones mientras una
condición es verdadera.

El ciclo do-while toma la forma:

do <proposición> while ( <expresión condicional> );

Esto es similar a la proposición iterativa while, pero asegura que el ciclo es ejecutado al menos una vez,
como la expresión condicional es evaluada sólo al final de cada iteración.

Ejemplos
do
{
a=a+1;
}
while ( a < 10 );

61
8. Operadores

El uso de operadores es central para C++, y es importante que cada programador comprenda cual es el
efecto de usar un operador, y las diferencias que pueden aparecer y ser en primera instancia irrelevantes,
pero alterar drásticamente el significado de un programa.

Los operadores pueden ser agrupados dentro de distintas clases:-

• Operadores relacionales
• Operadores binarios de bits
• Conectivos lógicos
• Operadores aritméticos
• En una expresión, cualquier número de operadores pueden ser usados para especificar valores
basados en variables y/o constantes. La manera en la cual esta expresión es evaluada es
conjuntamente determinada por la precedencia y la inclusión de paréntesis. Paréntesis '(' y ')' son
usados de la manera obvia.

% Es el cociente de la división. Ej: 7 /2 = 3 y sobra 1.  7%2=1

62
63
8.1. Operadores binarios.

Los operadores unitarios prefijos e infijos son usados por C++.

Operadores binarios sobre bits

Operador Descripción
& AND
^ OR exclusivo
| OR inclusivo
~ Not (operador prefijo unario)
<< Corrimiento izquierdo
>> Corrimiento derecho
Estos operadores son usados sobre cualquier tipo ordinal - esto es. char, int etc.

Ejemplos :-

1 & 2 es equivalente a 0
3 & 2 es equivalente a 0 2
1 | 2 es equivalente a 0 3
3 ^ 2 es equivalente a 0 1
1 | 2 es equivalente a 0 3
1 << 2 es equivalente a 0 4
4 << 3 es equivalente a 0 32
4 >> 2 es equivalente a 0 1
('a'^'a') es equivalente a 0 '\0'

64
8.2. Operadores lógicos

Operadores lógicos.

Operador Descripción
&& AND lógico
|| OR lógico
! NOT lógico
Estos operadores pueden ser usados sobre tipos ordinales - como char, int etc.

NOTA: Cualquier valor diferente de cero es tratado como un valor lógico verdadero en C++ (Obviamente 0 es
tratado como falso)

Ejemplos:

0 && 2 evalúa a falso (el valor 0)


3 && 2 evalúa a verdadero (algún valor no cero)
0 || 2 evalúa a verdadero (algún valor no cero)
0 || 0 evalúa to falso (el valor 0)
!-3 evalúa a falso (el valor 0)
!0 evalúa a verdadero (algún valor no cero)

El If aritmético

Un if aritmético toma la siguiente forma:

<condición> ? <expresión-verdadera> : <expresión-falsa>

La condición es evaluada, y si esta evaluación es verdadera, entonces la proposición expresión-verdadera es


evaluada. De lo contrario, la expresión-falsa es evaluada.

Por ejemplo, la siguiente expresión regresa 1 si n es mayor que 0, y 0 en caso contrario:

n>0 ? 1 : 0

65
8.3. Operadores sobrecargados

Cuando un operador estándar en C++ (tal como +) es usado en un programa, se llama a una función para
efectuar esta acción. Esto es posible para sobrecarga de funciones dentro de un programa, también es
posible para sobrecarga de operadores estándar en C++.

+, -, *, /, %
Los operadores aritméticos pueden ser sobrecargados en cualquier clase. Esto es muy útil cuando
las clases definen algún objeto para los cuales las operaciones aritméticas tienen su significado
convencional. Por ejemplo, estos deben de ser sobrecargados en una clase representando
fracciones, números complejos, etc.
&, |, ~, !, ^
Los operadores entre bits son sensibles a la sobrecarga únicamente en algunas situaciones, tales
como cuando se implementa un nuevo tipo que almacena enteros mayores que la implementación
del entero más grande.
=
Este es el operador de asignación. Esto es sobrecargado para más clases de objetos.
++, --, <<=, >>=,
Las notaciones abreviadas para la operación & su asignamiento puede ser sobrecarga de manera
obvia.
<, >, <=, >=, ==, !=
Esto operadores deben ser sobrecargados para proporcionar un orden parcial en un tipo de un
objeto. Por ejemplo si uno necesita tener clases de píxeles, un orden parcial de "brillantez" debe
hacer buen uso de los operadores relacionales.
<<, >>
Esto operadores son sobrecargados para un flujo de IO, y deben ser declarados como friends de la
clase iostream el cual soporta IO.
->, ->*, [ ]
Estos operadores controlan la desreferencia de apuntadores. Estos pueden ser útiles en clases para
representar arreglos dispersos.
&&,||
El AND y OR por ejemplo pueden ser sobrecargados en una clase representando una derivación
lógica de un conjunto de axiomas inusuales.
,, ( ), new, delete
La coma, el secuencial, los operadores new y delete pueden ser sobrecargados, pero se debe tener
cuidado cuando se eligen para hacer esto.

Esto permite la simplificación de funciones tales como:

String str = "The cat ";

str.Add("sat on the mat.");


str.Print();

Si la adición y las funciones de salida fueran sobrecargadas en los operadores += y la clase ostream <<, este
segmento de código debe ser:

String str = "The cat ";

str += "sat on the mat.";


cout << str << endl;

Las funciones que llevan a cabo esto pueden ser declaradas como:

class String {
friend ostream &operador <<(ostream &,String &);
public:
String(char *);
String &operador+=(char *);

private:
char *st;
};
66
String &String::operador+=(char *s)
{
int newlength;
char *pt;

newlength = strlen(st) + strlen(s) + 1;


pt = new char[newlength];
strcpy(pt,st);
strcat(pt,s);
delete st;
st = pt;
}

ostream &operator<<(ostream &os,String &s)


{
return os << s.st;
}

Es posible sobrecargar todos los operadores estándar mostrados anteriormente. Sin embargo, se debe tener
cuidado para hacer que todas las operaciones de sobrecarga parezcan naturales. Esto no debe tener efectos
laterales los cuales causen al programador problemas.

67
Operador "#" - Operador de preprocesador

Creación de macros.

El operador "#" sirve para dar órdenes o directivas al compilador.


Directiva define:
La directiva "#define", sirve para definir macros. Esto suministra un sistema para la sustitución de
palabras, con y sin parámetros.
Sintaxis:

#define <identificador_de_macro> <secuencia>

 Pueden colocarse tanto en la parte pública, como en el cuerpo del programa.

• El preprocesador sustituirá cada ocurrencia del <identificador_de_macro> en el fichero fuente,


por la <secuencia> aunque hay algunas excepciones.
• Cada sustitución se conoce como una expansión de la macro, y la secuencia es llamada a
menudo cuerpo de la macro.
• Si la secuencia no existe, el <identificador_de_macro> será eliminado cada vez que aparezca en
el fichero fuente.
• Después de cada expansión individual, se vuelve a examinar el texto expandido a la búsqueda de
nuevas macros, que serán expandidas a su vez. Esto permite la posibilidad de hacer macros
anidadas.

Restricciones a la expansión de macros:


• Si la nueva expansión tiene la forma de una directiva de preprocesador, no será reconocida como
tal.
• Las ocurrencias de macros dentro de literales, cadenas, constantes alfanuméricas o comentarios
no serán expandidas.
• Una macro no será expandida durante su propia expansión, así #define A A, no será expandida
indefinidamente.
• La macro puede ser una fórmula, y el nombre del fichero puede crearse usando esa fórmula.

68
Ejemplo:
#define suma(a,b) ((a)+(b))

Los paréntesis en el cuerpo de la macro son necesarios para que funcione correctamente en todos los
casos, lo veremos mucho mejor con otro ejemplo:

69
Directiva #include

La directiva "#include" sirve para insertar ficheros externos dentro de nuestro fichero de código
fuente. Estos ficheros son conocidos como ficheros incluidos, ficheros de cabecera o "headers".
Sintaxis:

1. #include <nombre de fichero cabecera>


2. #include "nombre de fichero de cabecera"
3. #include identificador_de_macro

El preprocesador elimina la línea "#include" y la sustituye por el fichero especificado.


El tercer caso halla el nombre del fichero como resultado de aplicar la macro.

La diferencia entre escribir el nombre del fichero entre "<>" o """", está en el algoritmo usado para
encontrar los ficheros a incluir.
• En el primer caso el preprocesador buscará en los directorios "include" definidos en el
compilador.
• En el segundo, se buscará primero en el directorio actual, es decir, en el que se encuentre el
fichero fuente, si el fichero no existe en ese directorio, se trabajará como el primer caso.
• Si se proporciona el camino como parte del nombre de fichero, sólo se buscará es ese
directorio.
• El tercer caso es "raro", no he encontrado ningún ejemplo que lo use, y yo no he recurrido
nunca a él. Pero el caso es que se puede usar, por ejemplo:
#define FICHERO "trabajo.h"

#include FICHERO

int main()
{
...
}

70
10. Funciones en C++

Las funciones son segmentos de código las cuales pueden ser invocadas por otras partes del programa.
Esto permite al código ser escrito con reusabilidad.

Una función podría ser razonablemente general y contener parte de código.


Si una parte de código es usado distintas veces en diferentes puntos en un programa es buena idea colocar
esto dentro de una función.

Una función puede ser llamada desde el cuerpo del programa, o también desde otra función.

La primera línea de la definición de función especifica:


su tipo de regreso, su nombre y su lista de argumentos.
Un ejemplo, una función que convierte un carácter en un número puede tener como primera línea la
siguiente:
int ctoi( char c )

Esto define que el tipo de regreso será int. El nombre es especificado como ctoi, y la función toma un
argumento de un carácter.

El uso de las funciones puede descomponerse en 3 elementos:


• El prototipo de la función.
• la definición de la función.
• La llamada de la función.

Las funciones pueden tomar cualquier número de argumentos como entrada.


Las funciones regresan UN valor de regreso como salida - se debe especificar el tipo de regreso del valor de
regreso en la definición de función.

Si una función no retorna nada, esta tiene un tipo de retorno de void.


La definición para una función la cual no toma ningún argumento y no retorna ningún valor podría ser como
esta :
void spam( void )
Una proposición return (en una función) causa que el programa salga inmediatamente de la función
posiblemente con un valor de regreso.
El tipo del valor regresado debe ser igual al tipo de regreso de la función, a menos que el tipo de regreso de
la función actúen sea void en cuyo caso ningún valor será retornado.

71
Esta es un función típica :

int factorial( int num )


{
int count, product;

if( num < 0 ) return( 0 );

for( count=num, product=1; count>1; count--) product *= count;

return( product );
}

Lo anterior define una función la cual puede ser usada desde cualquier parte dentro del programa para
calcular el factorial de un número.

Por ejemplo, el siguiente programa puede ser usado con la función anterior para calcular el factorial de los
números de cero a nueve.

int main( void )


{
int number, result;

for( number=0; number<10; number++)


{
result = factorial( number );
cout << number << " factorial = " << result << endl;
}

return( 0 );
}

La noticia es que main tiene un tipo de regreso de int - esto es porque cuando el programa termina esta
regresa un entero al shell. Se debe especificar el valor a ser regresado con la proposición return.

72
10.1 Los términos llamada por valor y llamada por referencia se refiere al mecanismo que se utiliza en el
proceso de “inserción”.
En la llamada por valor, solo se emplea el valor del argumento. El parámetro del argumento sustituye a su
parámetro formalcorrespondiente.
En la llamada por referencia, el argumento es una variable y ésta se emplea completamente. Dicha variable
argumento sustituye al parámetro formal, de modo que cualquier cambio que sufra el parámetro formal lo
sufrirá realmente la variable argumento.

Llamada de una función por referencia.

La forma de indicar un parámetro de llamada por referencia en una definición de función es agregar el signo
& al tipo de parámetro formal.

Ejemplo: Void funcion(int llamada_valor, int& llamada_ref)

73
10.2 Funciones en línea inline.

Se usa cuando queremos usar una función muy corta.


Consiste en poner toda la función en una sola línea, tanto prototipo como cuerpo de la función.
Se pone inline al principio de la linea.
Se escribe el cuerpo de la función después del prototipo.
No te olvides del punto y coma “ ; “.

Una definición de funció inline se puede ver como :


inline void print();

La palabra inline es una sugerencia (la cual puede ser ignorada) al compilador para que la siguiente función
pueda no ser llamada normalmente, pero el código de la función se instancia y puede ser insertado en
cualquier parte del programa para ser usado - sustituyendo el código de la función por el llamado a la
función.

Argumentos default

Cuando se construyen una definición de función, es posible dar a alguno o a todos sus argumentos valores
default. Por ejemplo, una función la cual toma tres argumentos como sigue,

void Function(int a, int b, int c)

se puede hacer que acepte sólo dos argumentos declarando esto como sigue:

void Function(int a, int b, int c = 10)

Esta ahora puede ser invocada en cada una de las siguientes formas (las cuales son todas equivalentes):

Function(9,4,10);
Function(9,4);

Si la función es llamada con sólo dos argumentos, entonces el tercero es inicializado con su valor default, en
este caso 10. A cualquiera o a todos los argumentos de una función se les pueden dar valores default de
esta manera. Sin embargo, a cada argumento se le puede dar un valor default sólo si el argumentos de la
derecha tiene uno.

void Function(int a = 1, int b = 2, int c = 3) // Ok


void Function(int a = 1, int b, int c = 3) // Incorrecto

Funciones Sobrecargadas

C++ permite más de una declaración de una función con el mismo nombre - a esto se le llama funciones
sobrecargadas. La única restricción es que todas las funciones con el mismo nombre deben tener
argumentos diferentes - de lo contrario el compilador no puede saber a cual de las funciones se esta
llamando. La función sobrecargada debe ser sólo usada donde se tenga un grupo de funciones las cuales
hagan cosas similares y necesiten datos ligeramente diferentes para cada una. Una función sobrecargada es
normalmente encontrada en clases .

Recursión

Una función la cual se llama asimisma (posiblemente de forma indirecta) es llamada una función recursiva.

74
11. Clases

• Una clase es la descripción de un objeto (por ejemplo, un cuadro de diálogo, un control, un menú,
etc.) del que se pueden generar una instancia y de las acciones que se pueden realizar con él.
• La combinación de los datos que se componen un objeto y de las acciones que se pueden realizar
con ellos dan lugar a la clase.
• Las clases pueden heredar funcionalidades de otras clases y así se pueden crear nuevas clases que
adquieren funcionalidades ya existentes.
• Una Clase está compuesta por dos partes:
o La declaración.
Usualmente un archivo con el sufijo .h, contiene la interfaz de la clase y la información
relacionada con los miembros de datos de la clase
o La Implementación.
Normalmente en un archivo de sufijo .cpp, define las funciones miembro.

• Una función tiene tantas variables miembro como funciones miembro.


• Un miembro (sea una variable miembro o una función miembro) puede ser público o privado.
• Normalmente, todas las variables miembro de una clase se etiquetan como miembros privados.
• Un miembro privado de una clase sólo se puede utilizar dentro de la definición de una función
miembro de la misma clase.
• El nombre de una función miembro de una clase se puede sobrecargar igual que el nombre de una
función ordinaria.
• Una clase puede utilizar otra clase como tipo de una variable miembro.
• Una función puede tener parámetros formales cuyos tipos sean clases.
• Una función puede devolver un objeto; es decir, el tipo del valer devuelto por una función puede ser
una clase.

Ejemplo:

75
• En este ejemplo, Cola es una Función Miembro.

• Las funciones miembro son declaradas en el cuerpo de la clase.


• Las funciones miembro se definidas independientemente.
• Es imposible acceder a los miembros privados de la clase desde fuera de dicha clase, solamente
son accesibles desde dentro excepto a través de funciones o clases Amigas.
• En algunos casos el uso de clases reemplaza el uso de struct.
• La sección privada puede solamente ser usado por funciones los cuales son miembros de la clase
que las declara.
• Las funciones y variables que se podrán usar en el programa son las públicas.
• Por defecto si no se escribe lo contrario, funciones y variables, siempre serán privadas.
• Un constructor es llamado en cada instancia de la clase, es decir, cuando un nuevo objeto de este
tipo de clase es creado.
• Un destructor es llamado cuando el objeto se da fuera de alcance, o cuando el objeto es borrado.

class string
{
public:
string ( char * initial ); // Constructor - llamado de inicialización.
~string ( void ); // Destructor - llamado al final del ambiente.

void output ( void ); // Una función pública que permite imprimir


// cadenas.
int getlength ( void ); // Otra función pública - uno de estos
// para retornar la longitud de la cadena.
private:
char *ptr; // Un dato miembro privado - no puede ser accedido
// por código fuera de la clase.
int length; // Otro dato miembro privado.
};

76
Variables Miembro

Acceso a variables miembro mediante “.” o “ ->”.


Las variables en las clases pueden ser declaradas en las secciones
• Públicas.
• privadas.
• Una tercera declaración, protegidas, es a menudo usado en conjunción con herencia.
(Descrita en la sección de herencia)

• Se puede acceder a ellas mediante los operadores punto (.) o la flecha (->).

77
Variables Públicas.
Cuando una variable es declarada en la sección pública de una clase, est significa que este puede ser
accesado y actualizado externamente así como internamente. Si una clase fue definida como sigue:
#include<iostream.h>

class Complex
{
public:
int real;
int imagine;
};

int main()
{
Complex comp;

comp.real = 5;
comp.imagine = 10;

return 0;
}

En este caso, esto parece prudente para suspender alguna función externa teniendo acceso a estos datos
miembro, y por lo tanto serían declaradas en la sección privada de la definición de clase. Pero rechazarían el
acceso externo a estos datos miembro, esto suspendería algunas alteraciones erróneas del dato
externamente por permitir acceso solamente através de un conjunto predefinido de funciones.

Variables Privadas.

Un tipo complejo de datos sería definido:-

class Complex
{
public:
Complex(int, int);
void setreal(int);
void steimag(int);
int getreal(void);
int getimag(void);
private:
int real;
int imagine;
};

Variables los cuales han sido decalaradas en la sección privada de la definición de clase no puede ser
accesada externamente de la clase. Por lo tanto, si un objeto complejo ha sido creado, la siguiente línea
causaría un error de compilación, como real es una variable miembro privada de la clase Complex.

Complex no(0,0);

no.real = 10; // Error al Compilar - el numerador es un dato miembro privado

78
Herencia. Clases Heredadas.

• Una clase puede heredar todos los datos y funciones que son miembros de otra clase (salvo las
funciones constructoras y destructoras).
• Una clase que herede todas las funciones de otra, puede cambiar la funcionalidad de cualquiera de
los datos y funciones heredadas, sin que afecte el funcionamiento de la clase padre o clase base.
• Cuando una clase hereda de más de una clase padre sp produce lo que se conoce como herencia
múltiple.
• La clase derivada puede ser la clase base de una nueva clase derivada.

En este ejemplo la clase base hace de tipo public.


• Cuando la clase padre es de tipo protected para la clase derivada, quiere decir, que la derivada
tendrá acceso a todos los datos privados de la padre.
• Cuando la clase padre es de tipo private para la derivada quiere decir que esta segunda no
tendrá acceso a los datos de la clase padre.

Existen tres alternativas para tipificar la clase base dentro de la heredada:


• public. Los miembros de la clase base mantienen el nivel de acceso de su clase base.
• private. Los miembros de la clase base que sean public o protected pasan a ser private en la
clase derivada.
• protected. Los miembros de la clase base que sean public pasan a ser protected en la clase
derivada.

79
Polimorfismo.

• Es la capacidad de usar una misma llamada a un método para diferentes clases y que el método
actué de manera dependiente del objeto.

• Este método se implementa en c++ por medio de las funciones Virtuales.


• Una función miembro virtual provee un medio para permitir que una clase base y las clases
derivadas se comporten de diferentes maneras.
• Una función miembro no virtual de una clase base, puede cumplir una funcionalidad determinada
para la clase base y para las clases derivadas. Sin embargo, dentro de esta función, se pueden
declarar y usar únicamente objetos de la clase base. Obviamente, no puede usar miembros de
datos que pertenezcan a las clases derivadas ya que aún ni siquiera se han creado.
• Si se define una función como si virtual, sin embargo, se puede definir una segunda versión de
esta función (con los mismos tipos de argumentos) en una clase derivada.

80
Clases y Estructuras Anidadas.

Una clase declarada en el interior de otra se denomina clase anidada, y se puede considerar como
una clase miembro.
Las Clases y las Estructuras se usan exactamente igual.

El identificador de una clase anidada está sujeto a las mismas reglas de acceso que los restantes
miembros.
Si una clase anidada se declara en la sección private de la clase circundante, la clase anidada será
utilizable sólo por los miembros datos de la clase que la circunde.
La clase que encierra puede acceder al nombre de la clase anidada sin resolución de ámbito.
Si un nombre de una clase anidada es accesible a una clase o función que no la circunda, se debe
aplicar el operador “ :: “.
Ejemplo de una clase anidada:

Para declarar una variable del tipo clase anidada se sigue el siguiente proceso:

Nombre_clase::Nombre_clase_anidada Nombre_Variable;

81
Ejemplo de una clase anidada:

82
Ejemplo de estructuras anidadas.

83
Clases y funciones Friend.

• Una función amiga, NO pertenece a la clase en la que está declarada.


• Una función amiga NO es un miembro de una clase
• Una función amiga, su prototipo de función se declara dentro de la clase a la que va poder
tener acceso precedido por la palabra clave friend.
• El cuerpo de la función amiga, se declara igual que una función normal, y NO como una
función que perteneciera a una clase con los ”::”.
• Una función amiga se define como una función no miembro normal
• Una función amiga tendrá acceso a todos los datos tanto privados como públicos de la clase
anfitriona.
• Una función (o clase) amiga tiene acceso a los datos miembros de la clase que la declara
como amiga.
• Se usan especialmente útil para la sobrecarga de operadores.

• Clases Friend.
• Para las clases hacemos lo mismo, según muestra el ejemplo.
• El cuerpo de la clase irá con el nombre de la clase original y no con el nombre de la clase
anfitriona, en este caso con Clase2

84
85
Clase Friend.
Ejemplo:

86
Template - Plantillas de función.

Escribir la declaración de template siempre antes de cada una de las funciones.


Para el caso de las definiciones lo mismo.

• Recordarás que no está permitido usar variables para indicar el tamaño de un array.
• C++ permite crear plantillas de funciones y plantillas de clases.

Sintaxis.
La sintaxis para declarar una plantilla de función es parecida a la de cualquier otra función, pero se
añade al principio una presentación de la clase que se usará como referencia en la plantilla:

template < class | typename <id> [,...] >

<tipo_retorno> <identificador>(<lista_de_parámetros>)
{
// Declaración de función
};

87
88
La sintaxis para declarar una plantilla de clase.

Es parecida a la de cualquier otra clase, pero se añade al principio una presentación de la clase que se
usará como referencia en la plantilla:

template <class|typename <id>[,...]>


class <identificador_de_plantilla>
{
// Declaración de funciones
// y datos miembro de la plantilla
};
Nota: La lista de clases que se incluye a continuación de la palabra reservada template se escriben
entre las llaves "<" y ">", en este caso esos símbolos no indican que se debe introducir un literal,
sino que deben escribirse.
Ejemplo:
template <class T1>
class Tabla
{
public:
Tabla();
~Tabla();
...
};
Del mismo modo, cuando tengamos que definir una función miembro fuera de la declaración de la
clase, tendremos que incluir la parte del template y como nombre de la clase incluir la plantilla antes
del operador de ámbito (::). Por ejemplo:
template <class T1>
Tabla<T1>::Tabla() {
// Definición del constructor
}

Plantillas de funciones.
Un ejemplo de plantilla de función puede ser esta que sustituye a la versión macro de max:
template <class T>
T max(T x, T y) {
return (x > y) ? x : y;
};
La ventaja de la versión en plantilla sobre la versión macro se manifiesta en cuanto a la seguridad de
tipos. Por supuesto, podemos usar argumentos de cualquier tipo, no han de ser necesariamente
clases. Pero cosas como estas darán error de compilación:
int a=2;
char b='j';

int c=max(a,b);
El motivo es que a y b no son del mismo tipo. Aquí no hay promoción implícita de tipos. Sin
embargo, están permitidas todas las combinaciones en las que los argumentos sean del mismo tipo o
clase, siempre y cuando que el operador > esté implementado para esa clase.
int a=3, b=5, c;
char f='a', g='k', h;
c = max(a,b);
h = max(f,g);

89
Plantilla para Tabla.
Ahora estamos en disposición de crear una plantilla a partir de la clase Tabla que hemos definido
antes. Esta vez podremos usar esa plantilla para definir Tablas de cualquier tipo de objeto.
template <class T>
class Tabla {
public:
Tabla(int nElem);
~Tabla();
T& operator[](int indice) { return pT[indice]; }

private:
T *pT;
int nElementos;
};

// Definición:
template <class T>
Tabla<T>::Tabla(int nElem) : nElementos(nElem) {
pT = new T[nElementos];
}

template <class T>


Tabla<T>::~Tabla() {
delete[] pT;
}
Dentro de la declaración y definición de la plantilla, podremos usar los parámetros que hemos
especificado en la lista de parámetros del "template" como si se tratase de comodines. Más adelante,
cuando creemos instancias de la plantilla para diferentes tipos, el compilador sustituirá esos
comodines por los tipos que especifiquemos.
Y ya sólo nos queda por saber cómo declarar Tablas del tipo que queramos. La sintaxis es:
<identificador_de_plantilla><<tipo/clase>> <identificador/constructor>;
Seguro que se ve mejor con un ejemplo, veamos como declarar Tablas de enteros, punto flotante o
valores booleanos:
Tabla<int> TablaInt(32); // Tabla de 32 enteros
Tabla<float> TablaFloat(12); // Tabla de 12 floats
Tabla<bool> TablaBool(10); // Tabla de 10 bools
Pero no es este el único modo de proceder. Las plantillas admiten varios parámetros, de modo que
también podríamos haber especificado el número de elementos como un segundo parámetro de la
plantilla:
template <class T, int nElementos>
class Tabla {
public:
Tabla();
~Tabla();
T& operator[](int indice) { return pT[indice]; }

private:
T *pT;
};

// Definición:
template <class T, int nElementos>
Tabla<T,nElementos>::Tabla() {
90
pT = new T[nElementos];
}

template <class T, int nElementos>


Tabla<T, nElementos>::~Tabla() {
delete[] pT;
}
La declaración de tablas con esta versión difiere ligeramente:
Tabla<int,32> TablaInt; // Tabla de 32 enteros
Tabla<float,12> TablaFloat; // Tabla de 12 floats
Tabla<bool,10> TablaBool; // Tabla de 10 bools
Esta forma tiene una limitación: el argumento nElementos debe ser una constante, nunca una
variable. Esto es porque el valor debe conocerse durante la compilación del programa. Las plantillas
no son definiciones de clases, sino plantillas que se usan para generar las clases que a su vez se
compilarán para crear el programa:
#define N 12
...
const n = 10;
int i = 23;

Tabla<int,N> TablaInt; // Legal, Tabla de 12 enteros


Tabla<float,3*n> TablaFloat; // Legal, Tabla de 30 floats
Tabla<char,i> TablaFloat; // Ilegal

91
Constructores y Destructores.
Es normal que una parte de un objeto necesite una inicialización antes de poder usarse.
Un constructor no es más que una función miembro que aglutina un conjunto de instrucciones que permiten
inicializar los objetos de una clase.

• El nombre de esa función debe coincidir con el nombre de la clase.

• El constructor recibe el mismo nombre que la clase:

nombreClase( );
• Sintaxis:
Nombre_De_Clase Nombre_de_Objeto ( Argumento del constructor);

El destructor recibe el mismo nombre que el constructor precedido de ~

~nombreClase( );

• Llamada especifica al constructor, ocurre en el cuepo del programa cuando un objeto inicializa el
constructor.
• Sintaxis:
Objeto=Nombre del constructor (Argumento);
Ejemplo:

Cuenta1= CuentaBancaria(23, 23,4);

92
Otro ejemplo de Constructor

93
Constructores II (Ampliación)
Los constructores son funciones miembro especiales que sirven para inicializar un objeto de una
determinada clase al mismo tiempo que se declara.
Los constructores tienen el mismo nombre que la clase, no retornan ningún valor y no pueden ser
heredados. Además deben ser públicos, no tendría ningún sentido declarar un constructor como
privado, ya que siempre se usan desde el exterior de la clase, ni tampoco como protegido, ya que no
puede ser heredado.
Añadamos un constructor a nuestra clase pareja:

94
Si una clase posee constructor, será llamado siempre que se declare un objeto de esa clase, y si
requiere argumentos, es obligatorio suministrarlos.
Por ejemplo, las siguientes declaraciones son ilegales:

La primera porque el constructor de "pareja" requiere dos parámetros, y no se suministran.


La segunda es ilegal por otro motivo más complejo. Aunque existiese un constructor sin parámetros,
no se debe usar esta forma para declarar el objeto, ya que el compilador lo considera como la
declaración de un prototipo de una función que devuelve un objeto de tipo "pareja" y no admite
parámetros. Cuando se use un constructor sin parámetros para declarar un objeto no se deben escribir
los paréntesis.
Y las siguientes declaraciones son válidas:

Cuando no especifiquemos un constructor para una clase, el compilador crea uno por defecto sin
argumentos. Por eso el ejemplo del capítulo anterior funcionaba correctamente. Cuando se crean
objetos locales, los datos miembros no se inicializarían, contendrían la "basura" que hubiese en la
memoria asignada al objeto. Si se trata de objetos globales, los datos miembros se inicializan a cero.
Para declarar objetos usando el constructor por defecto o un constructor que hayamos declarado sin
parámetros no se debe usar el paréntesis:

Se trata de un error frecuente cuando se empiezan a usar clases, lo correcto es declarar el objeto sin
usar los paréntesis:

Inicialización de objetos:
Hay un modo simplificado de inicializar los datos miembros de los objetos en los constructores.
Se basa en la idea de que en C++ todo son objetos, incluso las variables de tipos básicos como int,
char o float.
Según eso, cualquier variable (u objeto) tiene un constructor por defecto, incluso aquellos que son de
un tipo básico.
Sólo los constructores admiten inicializadores. Cada inicializador consiste en el nombre de la
variable miembro a inicializar, seguida de la expresión que se usará para inicializarla entre
paréntesis. Los inicializadores se añadirán a continuación del paréntesis cerrado que encierra a los
parámetros del constructor, antes del cuerpo del constructor y separado del paréntesis por dos puntos
":".
Por ejemplo, en el caso anterior de la clase "pareja":

Podemos sustituir el constructor por:

95
Por supuesto, también pueden usarse inicializadores en línea, dentro de la declaración de la clase.
Ciertos miembros es obligatorio inicializarlos, ya que no pueden ser asignados, por ejemplo las
constantes o las referencias. Es muy recomendable usar la inicialización siempre que sea posible en
lugar de asignaciones, ya que se desde el punto de vista de C++ es mucho más seguro.
Veremos más sobre este tema cuando veamos ejemplos de clases que tienen como miembros objetos
de otras clases.

Sobrecarga de constructores:
Además, también pueden definirse varios constructores para cada clase, es decir, la función
constructor puede sobrecargarse. La única limitación es que no pueden declararse varios
constructores con el mismo número y el mismo tipo de argumentos.
Por ejemplo, añadiremos un constructor adicional a la clase "pareja" que simule el constructor por
defecto:

De este modo podemos declarar objetos de la clase pareja especificando los dos argumentos o
ninguno de ellos, en este último caso se inicializarán los datos miembros con ceros.

Constructores con argumentos por defecto:


También pueden asignarse valores por defecto a los argumentos del constructor, de este modo
reduciremos el número de constructores necesarios.
Para resolver el ejemplo anterior sin sobrecargar el constructor suministraremos valores por defecto
nulos a ambos parámetros:

96
Asignación de objetos:
Probablemente ya lo imaginas, pero la asignación de objetos también está permitida. Y además
funciona como se supone que debe hacerlo, asignando los valores de los datos miembros.
Con la definición de la clase del último ejemplo podemos hacer lo que se ilustra en el siguiente:

La línea "par2 = par1;" copia los valores de los datos miembros de par1 en par2.

Constructor copia:
Un constructor de este tipo crea un objeto a partir de otro objeto existente. Estos constructores sólo
tienen un argumento, que es una referencia a un objeto de su misma clase.
En general, los constructores copia tienen la siguiente forma para sus prototipos:

De nuevo ilustraremos esto con un ejemplo y usaremos también "pareja":

97
Para crear objetos usando el constructor copia se procede como sigue:

También en este caso, si no se especifica ningún constructor copia, el compilador crea uno por
defecto, y su comportamiento es exactamente el mismo que el del definido en el ejemplo anterior.
Para la mayoría de los casos esto será suficiente, pero en muchas ocasiones necesitaremos redefinir
el constructor copia.

98
15. Librerías. Organización de archivos

Uso de librerías.
Hay 2 forma de hacerlo:
A. Incluyendo las definiciones de clases, función y la implementación en un archivo .h.
B. Incluyendo las definiciones de clases y función en un archivo .h y la implementación en un .cpp.
B) Para crear una clase dentro de una librería (archivo.h):
1. Crea un archivo libreria.h.
2. Declara y define la clase dentro de dicho archivo
3. En el archivo de código, archivo.cpp, inserta el #include"libreria.h".
4. También se puede poner al principio y al final de la librería .h la siguiente expresión, para evitar que
nos salga un error si empleamos una clase o librería que ya este hecha en otro lugar.
5. NO poner “ ; “ al final de los #include , #define ni #ifndef
#ifndef libreria_h
…..
Definición de la clase
….

#endif

En la librería.h añadir la siguiente línea:


#define libreria_h

En la librería.cpp añadir:
#include"libreria.h".
#include<iostream>
#include"todas las librerías empleadas".

99
Otro ejemplo similar:

100
101
B) Definición de una clase ADT (tipo de dato abstracto) en archivos individuales.

Podemos definir una ADT como una clase y colocar la definición de la clase y la implementación de sus
funciones miembro en archivos distintos.
1. Archivo de interfaz. Archivo de encabezado donde se coloca la definición de la clase.
• El nombre de este archivo debe de acabar en .h y no en cpp. Ejemplo: Archivo.h
• Contiene los prototipos de funciones y operadores sobrecargados que definen las operaciones básicas
del ADT.
• En este archivo pueden ir:
• La definición de la clase(aunque suele ir en el archivo de implementación).
• El prototipo de una función que servirá como operación del ADT, pero que no es ni miembro, ni
friend de la clase.
• El prototipo del operador sobrecargado que servirá como operación del ADT, pero que no es ni
miembro, ni friend de la clase.
2. Archivo de implementación. Aquí van colocados todas las definiciones de funciones y operadores
sobrecargados mencionados en el Archivo de interfaz.
• Este archivo debe de contener la directiva

#include”Archivo.h”

• Este archivo ha de llamarse igual que su archivo de interfaz


• El nombre de este archivo debe de acabar en .cpp.

Ejemplo: Archivo.cpp.

En este archivo pueden ir:


• La definición de una función que servirá como operación del ADT, pero que no es ni miembro ni
función friend de la clase.
• La definición de una función friend que servirá como operación del ADT.
• La definición de una función miembro.
• La definición de un operador sobrecargado que servirá como operación del ADT, pero que no es
ni miembro ni friend de la clase.
• La definición de un operador sobrecargado que servirá como operación del ADT, pero que no es
ni miembro ni friend de la clase.

Mira el ejemplo de la página siguiente.

102
Archivo de Encabezado (archivo.h)

//Archivo de encabezado lista.h


//Interfaz

#ifndef LISTA_H
#define LISTA_H

#include<iostream.h>

class Lista
{
prototipos de funcion
declaración de variables

};
#endif

Archivo de implementación (su nombre es igual al de su interfaz pero acabado en .cpp.

#ifndef LISTA_CPP En mayuscula.


#define LISTA_CPP
#include”lista.h”

#include <iostream.h>

tipo Clase::funcion(...)
{
…Definición de la clase…
};
#endif

Cuerpo del programa.

#include “lista.h” Añadir el nombre del archivo de interfaz entre “ “ y acabado en .h


#include”lista.cpp” Añadir el nombre del archivo de implementación entre “ “ y acabado en .cpp
……

103
Cuando el #include viene entre < > es que la librería pertenece a visual C++.
#include <iostream.h>

Cuando el #include viene entre “ “ es que la librería esta en el directorio del archivo.
#inlude “LibEdy.h”

Cuando programas en C++ no triviales son escritos, es normal dividir el código fuente dentro de diferentes
archivos.
• Si un programa consiste de sólo un archivo entonces cualquier cambio, por pequeño que sea,
significa que el archivo entero tiene que ser recompilado.
• Si esta por separado es posible que sólo un archivo deba ser recompilado por cada cambio.
Esto también hace que el programa sea más fácil de leer y modificar.

Es común que cada clase tenga su propio conjunto de archivos fuente.


Clase:
• Archivo de cabecera. archivo.h  Declaraciones (nombres de funciones o clases).
• Archivo de implementación  archivo.cpp  Definiciones (código del archivo de cabecera).
Por ejemplo, si una clase Stack ha sido escrita, entonces su declaración (nombre de función) debe ser
colocada en el archivo stack.h, y su definición (código de la función) en stack.cpp.

Esto significa que cuando un programa desea usar la clase stack, sólo necesita incluir el archivo de
encabezado stack, y será ligado con el archivo objeto stack.

Esto también significa que la clase Stack puede ser alterada mientras se separa completamente del código
del programa principal.

Encabezado de archivos: Coloca la declaración de las clases.


Archivos fuente: Coloca la definición de las clases.

104
Encabezado de Archivos
• El encabezado de los archivos es usado para almacenar información auxiliar tal como definición de
funciones y valores definidos.

Por ejemplo:
#define MY_TRUE 1
#define MY_FALSE 0

typedef My_Bool int;


...
• El Encabezado de archivos en C++ son usualmente sufijados con .H, y pueden ser incluidos dentro
de archivos fuente.
• El encabezado de archivos puede incluir otro encabezado de archivo.
• El encabezado de archivos son principalmente usados para decirle al compilador acerca de los
detalles de las funciones y clases en otros archivos fuente.

Hay 2 maneras de definir un #include:

#include<iostream.h>  El archivo está declarado en el compilador. < >

#include”iostream.h”  El archivo está declarado dentro de la carpeta. “ “

#define.
Una directiva #define indica al preprocesador que reemplace un símbolo por su valor en cualquier sitio
del archivo de programa. Aquí, el símbolo es NUMERO_UNO, y el valor es 1:

*define NUMERO UNO 1 // valor del símbolo #define

Una directiva #define le permite definir un nombre con significado de forma que el código no esté
lleno de números crípticos. Esto hace el código más legible. También puede definir una constante
en un lugar, de modo que si tiene que cambiarla más tarde, no tenga que buscar en todo el
programa las múltiples apariciones de esa constante.
Pero C++ también proporciona una forma mejor de declarar constantes, la declaración const.
Aquí tiene algunos ejemplos:

const int NUMERO_UNO = 1;


const char* OLD_FRIEND = "viejo amigo, por ahora.";

El enfoque const es normalmente mejor que #define porque es un tipo seguro. C++ comprueba para
asegurarse que los datos con los que se ha inicializado el símbolo son consistentes con el tipo
declarado después de la palabra clave const. Normalmente debería utilizar const en lugar de #define, a
no ser que vuelva a crear una macro de preprocesador de C++.

105
Archivos Fuente

Los archivos fuente, usualmente sufijados por .C , .cc , .CPP o .CXX (la ultimas dos son principalmente
encontradas sobre PCs), son usados para almacenar el código del programa principal y también las
definiciones de clases de funciones miembro.

#define BODY_TEMP 197

El archivo termometro.C contiene el código del programa:

#include "termometro.H"
#include <iostream>

main()
{
cout << "Mi temperatura es " << BODY_TEMP <<
" grados celcius." << endl;
exit(0);
}

106
Entrada y Salida de Archivos

Para usar entrada y salida de archivos de flujo en C++, en el archivo de encabezado deberá estar incluido
fstream.h.

#include <fstream.h>

fstream.h proporciona varios objetos los cuales permite un método ordenado de manejo de entrada y salida
de flujos y de archivos. Los tipos especificados en este archivo de encabezado son :-

• ifstream

Este es un flujo con el modo de inicio default para lectura

• ofstream

Este es un flujo con el modo de inicio default para escritura

• fstream

Este es la generalización de los dos de arriba - sin preferencia de lectura y escritura.

Cualquier n´mero de cualquier objeto puede ser justamente declarado como si fueran tipos de variables
ordinarios.

Abriendo un Archivo

Para ser capaz de interactuar con un archivo, este primero debe ser abierto lo cual puede ser hecho de
varias maneras para los varios tipos de flujo. El constructor (Esto es una función de flujo clases el cual
permite que los argumentos sean pasados en tiempo de definición) puede ser usado, o la acción open debe
ser usado en algun objeto de flujo en algun tiempo.

<fstream> <varname> ("<filename>")


o para definir un flujo, entonces unimos esto a un archivo:-
<fstream> <varname> ;
<varname>.open("<filename>")

En los ejmplos de arriba <ifstream> es usualmente usado para entrada, y <ofstream> para salida. <fstream>
es usado tipicamente cuando opciones especiales son deseadas. Un prototipo completo para la acción de
entrada de flujo es:-

void open(const char *name, int mode, int prot)


Name es el nombre del archivo a ser usado. Mode se refiere al modo-abrir el cual es definido en la clase
ios usando una enumeración:-
enum open_mode
{
in = 1, // El archivo es de entrada.
out = 2, // El archivo es de salida.
ate = 4, // Abre el archivo y busca el fin de archivo.
app = 8, // Abre el archivo y fuerza a todas añadir escritura.
trunc = 16, // Trunca e archivo a una longitud 0.
nocreate = 32, // No crea el archivo.
noreplace = 64, // No permite reemplazar un archivo nuevo en uno existente.
};

Un operador (::) es necesario para permitir al compilador identificar la clase correcta desde el cual coge esta
enumeración. Con las definiciones de modo_de_abrir, es posible unir las opciones - por ejemplo:-

filestream.open( "thefile", ios::out | ios::ate | ios::nocreate);

107
En una forma similar prot refiere a los archivos con el permiso de banderas como un entero. Este entero es
igual que la representación de números octales los cuales pueden ser usados con el comando de Unix
chmod.

Operaciones sobre u ararchivo abierto

Son posibles muchas operaciones. Estas son proporcionadas por las clases llamados ios, istream, ostream,
e iostream los cuales son heredados por las clases de entrada y salida de archivos. Estas funciones
incluyen:-

<< El operdor de salida - es usado de la misma forma como en la terminal IO, pero usa un formato diferente
para la salida. Por ejemplo: un entero para un flujo de archivo es sacado como un solo número binario,
mientras que cout primero convierte a una representació ASCII para tener una lectura legible.
>> Un operador de salida corresponde a un operador de salida de archivo
eof() Prueba si el final de archivo ha sido alcanzado
getline(char* ptr, int len, char delim='\n'); Esto es usado sobre una entrada de flujo de archivo permite que
un bloque de archivos sea leido dentro de un delimitador con el valor default del retorno de carro, o hasta la
logitud máxima del bloque (tipicamente la longitud del buffer).
putback(char); Este pone el caracter especificado en el buffer istream .
seekg(streamoff, seek_dir) / seekp(streamoff, seek_dir) Este permite un acceso directo a un offset el cual
puede ser especificado relativamente en el comienzo, fin o las posiciones corrientes de archivos dependen
del valor de seek_dir.
tellg() / tellp() Este retorna la posición corriente en el archivo.
Para más detalles sobre estas funciones se aconseja consultar las páginas del manual para

• fstream
• istream
• ostream
• iostream
• ios

Cerrando un Archivo

Para cerrar un archivo, la funcón close() es usado. Por ejemlpo:

ifstream infile( "data.in" );

if ( !infile )
{
cout << "Couldn't open file data.in" << endl;
return 1; // Finaliza la función con un código de error de 1
}

infile.close(); // Lectura de datos desde el archivo

108
Hola Mundo!

Parece tradicional en cualquier introducción de algún lenguaje de programación tener un ejemplo de un


programa 'Hola Mundo!', por lo tanto aquí tenemos una implementación en C++.

// Hola Mundo - Imprime Hola Mundo! a la salida estándar.

#include <iostream.h>

main()
{
cout << "Hola Mundo!" << endl;
}

Comentario

La primera línea de este programa es un comentario. En C++, cualquier cosa después de// hasta el final de la
ínea es considerada un comentario.

Por ejemplo:

// Un comentario

// Estos comentarios
// han sido colocados
// sobre distintas líneas.

Los comentarios en ANSI C están encerrados entre el símbolo /* y */, y pueden ser usados también en
programas de C++. Por ejemplo:

/* Un estilo de comentario */

/* Un comentario
espaciado
en diferentes
líneas */

El estilo de C++ para los comentarios es usualmente más fácil de leer y escribir, y es el estilo preferido para
los programas C++.

#include <iostream.h>

La segunda línea del programa es usada para incluir el archivo iostream.h. Ladirectiva #include dice al
compilador revisar el archivo mencionado(En este caso iostream.h), e insertarlo dentro del archivo fuente en
ese punto. Este archivo de encabezado es necesario para habilitar la función de salida, cout, usada má tarde
para trabajar en el programa.

main()

Esta función es el punto inicial para la ejecución de cualquier programa C++.

Cualquier programa escrito en C o C++ debe tener una función llamada main() en algún lugar, esta función
es llamada cuando el programa es ejecutado.

Otras funciones pueden ser escritas, y llamadas desde otras secciones del programa. Por ejemplo, el
programa Hello world puede ser escrito como:

#include <iostream.h>

main()

109
{
HolaMundo();
}

void HolaMundo()
{
cout << "Hola Mundo!" << endl;
}

void aquí especifica que la función HolaMundo() no regresa ningún valor.

cout << "Hello world!" << endl

La línea Hola Mundo! va a la salida est&andar. La cual es generalmente la pantalla del usuario.

El lenguaje C ensímismo no proporciona ningún constructor el cual pueda ser usado para imprimir las salidas
dentro de la pantalla del usuario, pero la librería de C++ permite la entrada y la salida usando flujos.

La inclusión de iostream.h en el programa significa que distintos flujos estándar son proporcionados
automáticamente. El flujo cout es usado para la salida a la pantalla del usuario, y el flujo cin es usado para
la entrada.

El operador << inserta datos dentro de un flujo. Por lo tanto la instrucción,

cout << "Hola Mundo!";

inserta la cadena Hola Mundo! dentro del flujo de salida. Es posible insertar más de un bloque de datos
dentro de un flujo con un sólo comando. Por ejemplo, la siguiente línea,

cout << "Hola Mundo," << " Yo soy " << 20 << " hoy";

inserta la línea Hola Mundo, Yo soy 20 hoy dentro del flujo de salida. Cualquiera de los tipos de datos
predefinidos en C++ pueden ser impresos usando el operador cout .

El operador endl inserta una línea nueva dentro del flujo, y también fluye al bufer de salida. También es
posible que fluya un flujo de salida sin una nueva línea, usando el operador flush . Si una salida no fluye,
entonces no se garantiza que la información sea desplegada inmediatamente.

110
C++

Vocabulario.

ADT. Tipo de dato abstracto.

Argumentos (de una función). Valor que se da a una función.


Es un valor, no un marcador (a diferencia del parámetro).
A una función se le pueden dar varios argumentos.
Los argumentos siempre son de un tipo.
Función. No devuelve valor al contrario que el procedimiento.
Prototipo de Función. La que se hace antes del inicio del programa.
Llamada de Función. La que se ejecuta en el cuerpo del programa.
Definición de Función. La que se hace después o fuera del programa, con el cuerpo de la función.

Parámetro formal. Son los nombres de las variables, marcadores de posición en la memoria del pc, el cual
representa el argumento.

Procedimiento. Si devuelve valor al contrario que la función.

Un objeto es una variable que además de tener asociado un valor, tiene asociadas funciones.
Función miembro es una función que está asociada a un objeto.
Indican qué tipos de cosas puede hacer una clase
Clases. Un tipo cuyas variables son objetos.

Métodos. Los métodos son la implementación de las funciones de las clases.


Miembro de datos. Un dato en una clase se almacena en una variable conocida como miembro de datos.
Modificador de acceso. Sería Public o Private o Protected.

Operador punto. Es el punto entre el objeto y la función miembro.


Operador resolución de alcance. Son los :: que se usan especificar el nombre de clase cuando damos la
definición de una función miembro. Ejemplo. Void Clase1::funcion1( )

Objeto invocador. Es el objeto cuyo nombre precede el operador punto.

Un objeto es una variable que tiene asociadas funciones. Estas funciones se llaman funciones miembro.
Una clase es un tipo cuyas variables son objetos. La clase del objeto (es decir, su tipo) determina cuáles
funciones miembro tiene dicho objeto.

111
La herencia es otra característica de la POO y consiste en que una clase comparte sus atributos y métodos
con otra. Así el código de una clase puede ser reutilizado por otra.
La herencia es un proceso mediante el cual un objeto puede adquirir las propiedades de otro objeto.

Constructores. Cuando creamos un objeto de una clase, siempre seguimos los mismos pasos para llamar a
un conjunto de métodos que inicialicen los datos del objeto. En C++, se define una función especial, el
constructor, que es llamada cuando se crea un nuevo objeto de la clase. Este constructor puede tomar
parámetros, como cualquier otra función.
Un constructor es una función especial que es miembro de esa clase y que tiene el mismo nombre de la
clase.
Es muy frecuente que una cierta parte de un objeto necesite una iniciación antes de que pueda ser utilizada;
como el requisito de iniciación es tan frecuente C++ permite que los objetos se den a sí mismos valores
iniciales cuando se crean. Esta iniciación automáticamente se lleva a cabo mediante el uso de una función
de construcción o constructor.

Sentencia. Es una línea y acaba con un ; .


• Ej: int numero (Declaración de una variable)
• Ej: numero=2+2.

Polimorfismo: Significa que un nombre se puede utilizar para especificar una clase genérica de acciones.

Flujo de C++. Es como un conducto de datos, que envía datos a varios sitios destino
Consola Win32. Son programas que se ejecutan en ventanas de DOS.

MFC. Classes de la fundación de Microsoft. Es un gran paquete de códigos preescritos y listos para usar.
POO:
Siglas de "Programación Orientada a Objetos". En inglés se pone al revés "OOP". La idea básica de este tipo
de programación es agrupar los datos y los procedimientos para manejarlos en una única entidad: el objeto.
Un programa es un objeto, que a su vez está formado de objetos. La idea de la programación estructurada
no ha desaparecido, de hecho se refuerza y resulta más evidente, como comprobarás cuando veamos
conceptos como la herencia.

Objeto:
Un objeto es una unidad que engloba en sí mismo datos y procedimientos necesarios para el tratamiento de
esos datos. Cada objeto contiene datos y funciones. Y un programa se construye como un conjunto de
objetos, o incluso como un único objeto.

Mensaje:
El mensaje es el modo en que se comunican los objetos entre si. En C++, un mensaje no es más que una
llamada a una función de un determinado objeto. Cuando llamemos a una función de un objeto, muy a
menudo diremos que estamos enviando un mensaje a ese objeto.
En este sentido, mensaje es el término adecuado cuando hablamos de programación orientada a objetos en
general.

Método:
Los mensajes que lleguen a un objeto se procesarán ejecutando un determinado método. En C++ un método
no es otra cosa que una función o procedimiento perteneciente a un objeto.

Clase:
Una clase se puede considerar como un patrón para construir objetos. En C++, un objeto es sólo un tipo de
variable de una clase determinada. Es importante distinguir entre objetos y clases, la clase es simplemente
una declaración, no tiene asociado ningún objeto, de modo que no puede recibir mensajes ni procesarlos,
esto únicamente lo hacen los objetos.

112
Interfaz:
Las clases y por lo tanto también los objetos, tienen partes públicas y partes privadas. Algunas veces
llamaremos a la parte pública de un objeto su interfaz. Se trata de la única parte del objeto que es visible
para el resto de los objetos, de modo que es lo único de lo que se dispone para comunicarse con ellos.

Herencia:
Veremos que es posible diseñar nuevas clases basándose en clases ya existentes. En C++ esto se llama
derivación de clases, y en POO herencia. Cuando se deriva una clase de otra, normalmente se añadirán
nuevos métodos y datos. Es posible que algunos de estos métodos o datos de la clase original no sean
válidos, en ese caso pueden ser enmascarados en la nueva clase o simplemente eliminados. El conjunto de
datos y métodos que sobreviven, es lo que se conoce como herencia.

Directivas de preprocesado. Son las que empiezan por # como incluye o define.
Literales. Son valores en un programa.
Sentencia. Es una declaración simple, comando o cálculo que termina con un punto y coma. La mayoría de
las veces no es mas que una línea de código.

OOP. Programación orientada a Objetos.


SDK. Kit de desarrollo de software de Windows.

113
FORMATOS

.dsw. Estos archivos son para manejar nuestro espacio de trabajo


.dsp. para manejar nuestro proyecto.
.cpp. Equivalente a C++. Archivo de código fuente. Aqui es donde se escribe el código en C++.

.h. Archivos de cabecera, están dentro del código fuente en los archivos C++.

* Para abrir un un programa ya existente, ir a Open WorkSpace.

114

You might also like