04.06.2015 Views

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

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>Manual</strong> <strong>básico</strong><br />

<strong>de</strong><br />

<strong>Programación</strong> <strong>en</strong><br />

<strong>C++</strong><br />

Apoyo a la Investigación C.P.D.<br />

Servicios Informáticos U.C.M.


INDICE<br />

PROGRAMACION ORIENTADA A OBJETOS<br />

1. INTRODUCCION.....................................................................................................4<br />

2. TIPOS DE DATOS ABSTRACTOS ( T.D.A. ).......................................................6<br />

3. CONCEPTOS DE ORIENTACION A OBJETOS................................................7<br />

3.1. Clases y métodos.................................................................................................7<br />

3.1.1. Tipos <strong>de</strong> clases............................................................................................7<br />

3.2. Objetos.................................................................................................................7<br />

3.3. M<strong>en</strong>sajes..............................................................................................................8<br />

3.3.1. Semejanzas <strong>en</strong>tre programación <strong>en</strong> l<strong>en</strong>guajes conv<strong>en</strong>cionales y P.O.O..8<br />

3.3.2. Difer<strong>en</strong>cias <strong>en</strong>tre programación <strong>en</strong> l<strong>en</strong>guajes conv<strong>en</strong>cionales y P.O.O..8<br />

3.4. Her<strong>en</strong>cia...............................................................................................................9<br />

3.5. Her<strong>en</strong>cia múltiple.............................................................................................10<br />

3.6. Enlace <strong>de</strong> métodos............................................................................................10<br />

3.7. Tipos g<strong>en</strong>éricos..................................................................................................10<br />

3.8. Asignación estática y dinámica <strong>de</strong> memoria..................................................11<br />

3.9. Polimorfismo.....................................................................................................11<br />

3.10. Reutilización.....................................................................................................11<br />

PROGRAMACION EN <strong>C++</strong><br />

INTRODUCCION...................................................................................................13<br />

<strong>C++</strong> COMO UN ''C MEJORADO''......................................................................15<br />

2.1. Com<strong>en</strong>tarios y <strong>de</strong>claraciones <strong>en</strong> <strong>C++</strong>...............................................................15<br />

2.2. Flujo <strong>de</strong> <strong>en</strong>trada/salida <strong>de</strong> <strong>C++</strong>........................................................................15<br />

2.3. Cómo crear nuevos tipos <strong>de</strong> datos <strong>en</strong> <strong>C++</strong>......................................................15<br />

2.4. Prototipos <strong>de</strong> función y verificación <strong>de</strong> tipo....................................................16<br />

2.5. Funciones <strong>en</strong> línea..............................................................................................16<br />

2.6. Parámetros por refer<strong>en</strong>cia................................................................................16<br />

2.7. El calificador const.............................................................................................17<br />

2.8. Asignación dinámica <strong>de</strong> memoria mediante new y <strong>de</strong>lete..............................18<br />

2.9. Operador <strong>de</strong> resolución <strong>de</strong> alcance unario......................................................18<br />

2.10. Homonimia <strong>de</strong> funciones..................................................................................18<br />

2.11. Plantillas <strong>de</strong> función.........................................................................................20<br />

PRIMERAS EXTENSIONES ORIENTADAS A OBJETOS.............................21<br />

3.1. Cómo poner <strong>en</strong> práctica un TDA con una clase.............................................21<br />

3.2. Alcance <strong>de</strong> clase y acceso a miembros <strong>de</strong> clase...............................................22<br />

3.3. Cómo controlar el acceso a miembros.............................................................23<br />

3.4. Cómo inicializar objetos <strong>de</strong> clase: constructores............................................24<br />

3.5. Destructores.......................................................................................................25


3.6. Cuándo son llamados los <strong>de</strong>structores y constructores.................................26<br />

3.7. Asignación por omisión <strong>en</strong> copia a nivel <strong>de</strong> miembro....................................26<br />

CLASES....................................................................................................................27<br />

4.1. Objetos constantes y funciones miembro const...............................................27<br />

4.2. Composición: clases como miembros <strong>de</strong> otras clases.....................................28<br />

4.3. Funciones amigo y clases amigo.......................................................................28<br />

4.4. Cómo utilizar un apuntador this......................................................................29<br />

4.5. Asignación dinámica <strong>de</strong> memoria mediante new y <strong>de</strong>lete..............................30<br />

4.6. Miembros <strong>de</strong> clase estáticos..............................................................................30<br />

4.7. Clases cont<strong>en</strong>edor e iteradores.........................................................................30<br />

4.8. Clases plantilla...................................................................................................31<br />

4.9. Clases abstractas................................................................................................32<br />

HOMONIMIA DE OPERADORES......................................................................33<br />

5.1. Fundam<strong>en</strong>tos <strong>de</strong> la homonimia <strong>de</strong> operadores...............................................33<br />

5.2. Restricciones sobre la homonimia <strong>de</strong> operadores..........................................33<br />

5.3. Homonimia <strong>de</strong> operadores <strong>de</strong> inserción y <strong>de</strong> extracción <strong>de</strong> flujo..................34<br />

5.4. Homonimia <strong>de</strong> operadores unarios..................................................................34<br />

5.5. Homonimia <strong>de</strong> operadores binarios.................................................................34<br />

5.6. Estudio <strong>de</strong> caso: una clase array......................................................................35<br />

5.7. Conversión <strong>en</strong>tre tipos......................................................................................35<br />

6. HERENCIA..............................................................................................................36<br />

6.1. Tipos <strong>de</strong> her<strong>en</strong>cia...............................................................................................37<br />

6.2. Clases base públicas, protegidas y privadas....................................................37<br />

6.3. Construcción y <strong>de</strong>strucción...............................................................................38<br />

6.4. Her<strong>en</strong>cia múltiple..............................................................................................38<br />

7. POLIMORFISMO...................................................................................................39<br />

8. PLANTILLAS PARA LOS NODOS.....................................................................40<br />

9. COMPILAMOS UN PROGRAMA.......................................................................43<br />

9.1. Pasos <strong>de</strong> la compilación.....................................................................................43<br />

10. FLUJO DE ENTRADA/SALIDA DE <strong>C++</strong>..........................................................45<br />

10.1. Archivos <strong>de</strong> cabecera <strong>de</strong> biblioteca iostream.................................................45<br />

10.2. Funciones miembro get y getline....................................................................45<br />

10.3. Entradas/salidas sin formato utilizando read, gcount y write......................46<br />

10.4. Manipuladores <strong>de</strong> flujo...................................................................................46<br />

11. EJERCICIOS.........................................................................................................47<br />

12. BIBLIOGRAFIA...................................................................................................59


1. INTRODUCCION<br />

<strong>C++</strong> es una mejoría sobre muchas <strong>de</strong> las características <strong>de</strong> C, y proporciona<br />

capacida<strong>de</strong>s <strong>de</strong> P.O.O. que promete mucho para increm<strong>en</strong>tar la productividad, calidad y<br />

reutilización <strong>de</strong>l software.<br />

En C, la unidad <strong>de</strong> programación es la función, con lo cual, se trata <strong>de</strong> una<br />

programación ori<strong>en</strong>tada a la acción.<br />

En <strong>C++</strong>, la unidad <strong>de</strong> programación es la clase a partir <strong>de</strong> la cual, los objetos son<br />

producidos. Se trata, pues, <strong>de</strong> una programación ori<strong>en</strong>tada al objeto.<br />

Las bibliotecas estándar <strong>de</strong> <strong>C++</strong> proporcionan un conjunto ext<strong>en</strong>so <strong>de</strong> capacida<strong>de</strong>s <strong>de</strong><br />

<strong>en</strong>trada/salida. <strong>C++</strong> usa <strong>en</strong>tradas/salidas <strong>de</strong> tipo seguro; no podrán introducirse datos<br />

equivocados <strong>de</strong>ntro <strong>de</strong>l sistema.<br />

Se pue<strong>de</strong>n especificar <strong>en</strong>tradas/salidas <strong>de</strong> tipos <strong>de</strong>finidos por el usuario, así como <strong>de</strong><br />

tipos estándar. Esta ext<strong>en</strong>sibilidad es una <strong>de</strong> las características más valiosas <strong>de</strong> este<br />

l<strong>en</strong>guaje <strong>de</strong> programación.<br />

<strong>C++</strong> permite un tratami<strong>en</strong>to común <strong>de</strong> <strong>en</strong>tradas/salidas <strong>de</strong> tipos <strong>de</strong>finidos por usuario.<br />

Este tipo <strong>de</strong> estado común facilita el <strong>de</strong>sarrollo <strong>de</strong> software <strong>en</strong> g<strong>en</strong>eral y <strong>de</strong> la<br />

reutilización <strong>de</strong> software <strong>en</strong> particular.<br />

La salida <strong>de</strong> flujo pue<strong>de</strong> ser ejecutada mediante el operador <strong>de</strong> inserción <strong>de</strong> flujo :


A continuación se muestra dos tablas <strong>de</strong> palabras reservadas <strong>en</strong> <strong>C++</strong> :<br />

C y <strong>C++</strong><br />

auto break case char const<br />

continue <strong>de</strong>fault do double else<br />

<strong>en</strong>um extern float for goto<br />

if int long register return<br />

short signed sizeof static struct<br />

switch type<strong>de</strong>f union unsigned void<br />

volatile while<br />

asm<br />

catch<br />

class<br />

<strong>de</strong>lete<br />

fri<strong>en</strong>d<br />

inline<br />

new<br />

operator<br />

private<br />

<strong>C++</strong> únicam<strong>en</strong>te<br />

Medio <strong>de</strong>finido por la puesta <strong>en</strong> práctica <strong>de</strong> l<strong>en</strong>guaje <strong>de</strong> <strong>en</strong>samble a lo<br />

largo <strong>de</strong> <strong>C++</strong>. ( Vea los manuales correspondi<strong>en</strong>tes a su sistema).<br />

Maneja una excepción g<strong>en</strong>erada por un throw.<br />

Define una nueva clase. Pue<strong>de</strong>n crearse objetos <strong>de</strong> esta clase.<br />

Destruye un objeto <strong>de</strong> memoria creado con new.<br />

Declara una función o una clase que sea un ''amigo'' <strong>de</strong> otra clase. Los<br />

amigos pue<strong>de</strong>n t<strong>en</strong>er acceso a todos los miembros <strong>de</strong> datos y a todas las<br />

funciones miembro <strong>de</strong> una clase.<br />

Avisa al compilador que una función particular <strong>de</strong>berá ser g<strong>en</strong>erada <strong>en</strong><br />

línea, <strong>en</strong> vez <strong>de</strong> requerir <strong>de</strong> una llamada <strong>de</strong> función.<br />

Asigna dinámicam<strong>en</strong>te un objeto <strong>de</strong> memoria <strong>en</strong> la memoria adicional<br />

disponible para el programa <strong>en</strong> tiempo <strong>de</strong> ejecución. Determina<br />

automáticam<strong>en</strong>te el tamaño <strong>de</strong>l objeto.<br />

Declara un operador ''homónimo''.<br />

Un miembro <strong>de</strong> clase accesible a funciones miembro y a funciones<br />

fri<strong>en</strong>d <strong>de</strong> la clase <strong>de</strong> miembros private.<br />

protected Una forma ext<strong>en</strong>dida <strong>de</strong> acceso private; también se pue<strong>de</strong> t<strong>en</strong>er acceso a<br />

los miembros protected por funciones miembro <strong>de</strong> clases <strong>de</strong>rivadas y<br />

amigos <strong>de</strong> clases <strong>de</strong>rivadas.<br />

public<br />

template<br />

this<br />

throw<br />

try<br />

virtual<br />

Un miembro <strong>de</strong> clase accesible a cualquier función.<br />

Declara cómo construir una clase o una función, usando una variedad <strong>de</strong><br />

tipos.<br />

Un apuntador <strong>de</strong>clarado <strong>en</strong> forma implícita <strong>en</strong> toda función <strong>de</strong> miembro<br />

no static <strong>de</strong> una clase. Señala al objeto al cual esta función miembro ha<br />

sido invocada.<br />

Transfiere control a un manejador <strong>de</strong> excepción o termina la ejecución<br />

<strong>de</strong>l programa si no pue<strong>de</strong> ser localizado un manejador apropiado.<br />

Crea un bloque que conti<strong>en</strong>e un conjunto <strong>de</strong> números que pudieran<br />

g<strong>en</strong>erar excepciones, y habilita el manejo <strong>de</strong> excepciones para cualquier<br />

excepción g<strong>en</strong>erada.<br />

Declara una función virtual.


2. <strong>C++</strong> COMO UN ''C MEJORADO''<br />

2.1. COMENTARIOS Y DECLARACIONES EN <strong>C++</strong><br />

<strong>C++</strong> permite empezar un com<strong>en</strong>tario con // y usar el resto <strong>de</strong> la línea para texto <strong>de</strong>l<br />

com<strong>en</strong>tario; el fin <strong>de</strong> la línea da <strong>de</strong> manera automática por terminado el com<strong>en</strong>tario.<br />

También es aceptable la forma <strong>de</strong> C : /* */.<br />

En <strong>C++</strong>, a difer<strong>en</strong>cia <strong>de</strong> C, las <strong>de</strong>claraciones pue<strong>de</strong>n ser colocadas <strong>en</strong> cualquier parte<br />

<strong>de</strong> un <strong>en</strong>unciado ejecutable, siempre y cuando las <strong>de</strong>claraciones antecedan el uso <strong>de</strong> lo<br />

que se está <strong>de</strong>clarando. También, las variables pue<strong>de</strong>n ser <strong>de</strong>claradas <strong>en</strong> la sección <strong>de</strong><br />

inicialización <strong>de</strong> una estructura for; dichas variables se manti<strong>en</strong><strong>en</strong> <strong>en</strong> alcance hasta el<br />

final <strong>de</strong>l bloque <strong>en</strong> el cual la estructura for está <strong>de</strong>finida.<br />

El alcance <strong>de</strong> una variable local <strong>C++</strong> empieza <strong>en</strong> su <strong>de</strong>claración y se exti<strong>en</strong><strong>de</strong> hasta la<br />

llave <strong>de</strong>recha <strong>de</strong> cierre. Las <strong>de</strong>claraciones <strong>de</strong> variables no pue<strong>de</strong>n ser colocadas <strong>en</strong> la<br />

condición <strong>de</strong> una estructura while, do/while, for o if.<br />

2.2. FLUJO DE ENTRADA/SALIDA DE <strong>C++</strong><br />

<strong>C++</strong> ofrece una alternativa a las llamadas <strong>de</strong> función printf y scanf para manejar la<br />

<strong>en</strong>trada/salida <strong>de</strong> los tipos y ca<strong>de</strong>nas <strong>de</strong> datos estándar. Así, <strong>en</strong> lugar <strong>de</strong> printf usamos el<br />

flujo estándar <strong>de</strong> salida cout y el operador > (''obt<strong>en</strong>er <strong>de</strong>''). Estos<br />

operadores <strong>de</strong> inserción y extracción <strong>de</strong> flujo, a difer<strong>en</strong>cia <strong>de</strong> printf y scanf, no<br />

requier<strong>en</strong> <strong>de</strong> ca<strong>de</strong>nas <strong>de</strong> formato y <strong>de</strong> especificadores <strong>de</strong> conversión para indicar los<br />

tipos <strong>de</strong> datos que son extraídos o introducidos.<br />

Para utilizar <strong>en</strong>tradas/salidas <strong>de</strong> flujo, se <strong>de</strong>be incluir el archivo <strong>de</strong> cabecera<br />

iostream.h.<br />

2.3. COMO CREAR NUEVOS TIPOS DE DATOS EN <strong>C++</strong><br />

<strong>C++</strong> proporciona la capacidad <strong>de</strong> crear tipos <strong>de</strong>finidos por el usuario mediante el uso<br />

<strong>de</strong> las palabras reservadas <strong>en</strong>um, struct, union y la nueva palabra reservada class. A<br />

difer<strong>en</strong>cia <strong>de</strong> C, una <strong>en</strong>umeración ( <strong>en</strong>um ) <strong>en</strong> <strong>C++</strong>, cuando se <strong>de</strong>clara, se convierte <strong>en</strong><br />

un tipo nuevo. Para <strong>de</strong>clarar la variable <strong>de</strong>l nuevo tipo, la palabra reservada <strong>en</strong>um no es<br />

requerida. Lo mismo para struct, union y class. Los nombres <strong>de</strong> etiqueta pue<strong>de</strong>n ser<br />

utilizados para <strong>de</strong>clarar variables. Las <strong>en</strong>umeraciones por omisión son evaluadas<br />

iniciándose <strong>en</strong> cero.


2.4. PROTOTIPOS DE FUNCION Y VERIFICACION DE TIPO<br />

<strong>C++</strong> requiere que se <strong>de</strong>clar<strong>en</strong> todos los parámetros <strong>de</strong> función <strong>en</strong> los paréntesis <strong>de</strong> la<br />

<strong>de</strong>finición <strong>de</strong> función y <strong>de</strong>l prototipo. Una lista vacía <strong>de</strong> parámetros se especifica<br />

escribi<strong>en</strong>do void o absolutam<strong>en</strong>te nada <strong>en</strong> los paréntesis.<br />

2.5. FUNCIONES EN LINEA<br />

Exist<strong>en</strong> funciones <strong>en</strong> línea que ayudan a reducir la sobrecarga por llamadas <strong>de</strong> función<br />

especial para pequeñas funciones. El compilador pue<strong>de</strong> ignorar el calificador inline y<br />

típicam<strong>en</strong>te así lo hará para todo, a excepción <strong>de</strong> las funciones más pequeñas. El<br />

calificador inline <strong>de</strong>berá ser utilizado sólo tratándose <strong>de</strong> funciones pequeñas, <strong>de</strong> uso<br />

frecu<strong>en</strong>te. Usa funciones inline pue<strong>de</strong> reducir el tiempo <strong>de</strong> ejecución, pero pue<strong>de</strong><br />

aum<strong>en</strong>tar el tamaño <strong>de</strong>l programa.<br />

Ejemplo:<br />

// Usamos la función inline para calcular el volum<strong>en</strong> <strong>de</strong> un cubo.<br />

#inclu<strong>de</strong> <br />

inline float cubo( const float s ) { return s * s * s; }<br />

main( )<br />

{<br />

cout > lado;<br />

cout


Las variables <strong>de</strong> refer<strong>en</strong>cia <strong>de</strong>b<strong>en</strong> ser inicializadas <strong>en</strong> sus <strong>de</strong>claraciones, y no pue<strong>de</strong>n<br />

ser reasignadas como seudónimos a otras variables.<br />

Cuando se regresa un apuntador o una refer<strong>en</strong>cia a una variable <strong>de</strong>clarada <strong>en</strong> la función<br />

llamada, la variable <strong>de</strong>berá ser <strong>de</strong>clarada static <strong>de</strong>ntro <strong>de</strong> dicha función.<br />

Las refer<strong>en</strong>cias pue<strong>de</strong>n ser usadas como argum<strong>en</strong>tos <strong>de</strong> funciones y regresar valores.<br />

Ejemplo:<br />

int ix; /* ix es la variable ''real'' */<br />

int &rx = ix; /* rx es el ''alias'' <strong>de</strong> ix */<br />

ix = 1; /* también rx == 1 */<br />

rx = 2; /* también ix == 2 */<br />

2.7. EL CALIFICADOR CONST<br />

El calificador const se usa <strong>en</strong> la lista <strong>de</strong> parámetros <strong>de</strong> una función para especificar que<br />

un argum<strong>en</strong>to pasado a la función no es modificable <strong>en</strong> dicha función. También pue<strong>de</strong><br />

ser utilizado para <strong>de</strong>clarar las llamadas ''variables constantes''. Estas pue<strong>de</strong>n ser<br />

colocadas <strong>en</strong> cualquier parte <strong>en</strong> que se espere una expresión constante. También <strong>en</strong><br />

archivos <strong>de</strong> cabecera.<br />

La variable constante <strong>de</strong>be ser inicializada al <strong>de</strong>clararse.<br />

Otro uso común para el calificador const es para po<strong>de</strong>r <strong>de</strong>clarar un apuntador<br />

constante.<br />

Tabla con expresiones <strong>de</strong> <strong>de</strong>claración <strong>de</strong> constantes:<br />

DECLARACION<br />

const tipo nombre = valor;<br />

Tipo constante.<br />

NOMBRE ES...<br />

tipo *const nombre = valor;<br />

const tipo *nombre = valor;<br />

Apuntador constante a tipo.<br />

(Variable) apuntador a la constante<br />

tipo.<br />

const tipo *const nombre = valor; Apuntador constante a tipo<br />

constante.


2.8. ASIGNACION DINAMICA DE MEMORIA MEDIANTE NEW Y DELETE<br />

En <strong>C++</strong>, el <strong>en</strong>unciado<br />

ptr = new typeName;<br />

asigna memoria para un objeto <strong>de</strong>l tipo typeName. El operador new crea<br />

automáticam<strong>en</strong>te un objeto <strong>de</strong>l tamaño apropiado, y regresa un apuntador (ptr)<strong>de</strong>l tipo<br />

apropiado. Si mediante new no se pue<strong>de</strong> asignar memoria, se regresa un apuntador nulo.<br />

Para liberar el espacio para este objeto se usa <strong>de</strong>lete ptr;<br />

El operador <strong>de</strong>lete sólo pue<strong>de</strong> ser utilizado para <strong>de</strong>sasignar memoria ya asignada<br />

mediante el operando new.<br />

2.9. OPERADOR DE RESOLUCION DE ALCANCE UNARIO<br />

Es posible <strong>de</strong>clarar variables locales y globales con un mismo nombre. <strong>C++</strong> dispone<br />

<strong>de</strong>l operador <strong>de</strong> resolución <strong>de</strong> alcance unario ( :: ) para t<strong>en</strong>er acceso a una variable<br />

global cuando está <strong>en</strong> alcance una variable local con el mismo nombre. No pue<strong>de</strong> ser<br />

utilizado para t<strong>en</strong>er acceso a una variable <strong>de</strong>l mismo nombre <strong>en</strong> un bloque externo.<br />

Ejemplo:<br />

#inclu<strong>de</strong> <br />

float v;<br />

int main( )<br />

{<br />

int v = 7;<br />

::v = 10.5; // Utilizar la variable global v<br />

cout


Ejemplo:<br />

// Definimos dos funciones distintas max( ), una que regrese el mayor <strong>de</strong><br />

// dos <strong>en</strong>teros y otra que regrese el mayor <strong>de</strong> dos strings.<br />

#inclu<strong>de</strong> <br />

int max( int a, int b )<br />

{<br />

if ( a > b ) return a;<br />

return b;<br />

}<br />

char *max( char *a, char *b )<br />

{<br />

if ( strcmp (a,b) > 0 ) return a;<br />

return b;<br />

}<br />

int main( )<br />

{<br />

printf ( ''max( 19, 69 ) = %d\n'', max( 19, 69 ) );<br />

printf ( ''max( abc,<strong>de</strong>f ) = %s\n'', max( ''abc'',''<strong>de</strong>f'' ) );<br />

return 0;<br />

}<br />

El programa <strong>de</strong>l ejemplo <strong>de</strong>fine dos funciones que difier<strong>en</strong> <strong>en</strong> su lista <strong>de</strong> parámetros,<br />

<strong>de</strong> ahí que <strong>de</strong>fina dos funciones distintas.<br />

Las refer<strong>en</strong>cias se pue<strong>de</strong>n usar para proveer una función con un alias <strong>de</strong> un argum<strong>en</strong>to<br />

real <strong>de</strong> llamada <strong>de</strong> función. Esto permite cambiar el valor <strong>de</strong>l argum<strong>en</strong>to <strong>de</strong> llamada <strong>de</strong><br />

función tal como se conoce <strong>de</strong> otros l<strong>en</strong>guajes <strong>de</strong> programación <strong>de</strong> llamada-porrefer<strong>en</strong>cia:<br />

void mira( int porValor, int &porRefer<strong>en</strong>cia )<br />

{<br />

porValor = 42;<br />

porRefer<strong>en</strong>cia = 42;<br />

}<br />

void mar( )<br />

{<br />

int ix, jx;<br />

ix = jx = 1;<br />

mira( ix, jx );<br />

// ix == 1, jx == 42<br />

}


2.11. PLANTILLAS DE FUNCION<br />

Las plantillas <strong>de</strong> función permit<strong>en</strong> la creación <strong>de</strong> funciones que ejecut<strong>en</strong> las mismas<br />

operaciones sobre distintos tipos <strong>de</strong> datos, pero la plantilla <strong>de</strong> función se <strong>de</strong>fine sólo una<br />

vez.<br />

Las plantillas <strong>de</strong> función proporcionan, como las macros, una solución compacta, pero<br />

permit<strong>en</strong> verificación completa <strong>de</strong> tipo.<br />

Todas las <strong>de</strong>finiciones <strong>de</strong> plantillas <strong>de</strong> función empiezan con la palabra reservada<br />

template ( ver apdo.4.8, pág. 31 ), seguida por una lista <strong>de</strong> parámetros formales a la<br />

plantilla <strong>de</strong> función <strong>en</strong>cerrados <strong>en</strong> corchetes angulares ( < >). Cada parámetro formal es<br />

precedido por la palabra reservada class. A continuación se coloca la <strong>de</strong>finición <strong>de</strong><br />

función y se <strong>de</strong>fine como cualquier otra función.


3. PRIMERAS EXTENSIONES ORIENTADAS A OBJETOS<br />

3.1. COMO PONER EN PRACTICA UN TDA CON UNA CLASE<br />

Las clases permit<strong>en</strong> que el programador mo<strong>de</strong>le objetos que ti<strong>en</strong><strong>en</strong> atributos<br />

(miembros <strong>de</strong> datos) y comportami<strong>en</strong>tos u operaciones (funciones miembro). Los tipos<br />

conti<strong>en</strong><strong>en</strong> miembros <strong>de</strong> datos y funciones miembro, y son <strong>de</strong>finidos mediante la palabra<br />

reservada class.<br />

El nombre <strong>de</strong> la clase (una vez <strong>de</strong>finida) pue<strong>de</strong> ser utilizado para <strong>de</strong>clarar objetos <strong>de</strong><br />

dicha clase.<br />

Ejemplo:<br />

class Punto // Declaración <strong>de</strong> la clase Punto.<br />

{<br />

int _x, _y; // Coor<strong>de</strong>nadas <strong>de</strong>l punto.<br />

public: // Principio <strong>de</strong> la <strong>de</strong>claración <strong>de</strong> interface.<br />

void setX (const int val);<br />

void setY (const int val);<br />

int getX( ) {return _x;}<br />

int getY( ) {return _y;}<br />

};<br />

Punto apunto; // Definición <strong>de</strong>l objeto apunto.<br />

La <strong>de</strong>finición <strong>de</strong> una clase comi<strong>en</strong>za con la palabra reservada class . El cuerpo <strong>de</strong> la<br />

<strong>de</strong>finición <strong>de</strong> clase se <strong>de</strong>limita mediante llaves. La <strong>de</strong>finición <strong>de</strong> clase termina con un<br />

punto y coma. En el cuerpo <strong>de</strong> la <strong>de</strong>finición exist<strong>en</strong> partes nuevas: la etiqueta public: y<br />

private: se conoc<strong>en</strong> como especificadores <strong>de</strong> acceso <strong>de</strong> miembro. Cualquier miembro<br />

<strong>de</strong> datos o función miembro <strong>de</strong>clarado <strong>de</strong>spués <strong>de</strong>l especificador <strong>de</strong> acceso <strong>de</strong> miembro<br />

public: (y antes <strong>de</strong>l sigui<strong>en</strong>te especificador <strong>de</strong> acceso <strong>de</strong> miembro) es accesible,<br />

siempre que el programa t<strong>en</strong>ga acceso a un objeto <strong>de</strong> la clase. Cualquier miembro <strong>de</strong><br />

datos o función miembro <strong>de</strong>clarada <strong>de</strong>spués <strong>de</strong>l especificador <strong>de</strong> acceso <strong>de</strong> miembro<br />

private: (y hasta el sigui<strong>en</strong>te especificador <strong>de</strong> acceso <strong>de</strong> miembro) sólo es accesible a<br />

las funciones miembro <strong>de</strong> la clase.<br />

Estos especificadores pue<strong>de</strong>n aparecer varias veces <strong>en</strong> una <strong>de</strong>finición <strong>de</strong> clase. Por<br />

<strong>de</strong>fecto, los elem<strong>en</strong>tos <strong>de</strong> las clases son privados ( private: ).<br />

Por lo regular, los miembros <strong>de</strong> datos aparec<strong>en</strong> listados <strong>en</strong> la porción private: <strong>de</strong> una<br />

clase, y normalm<strong>en</strong>te, las funciones <strong>de</strong> miembro aparec<strong>en</strong> listadas <strong>en</strong> la porción public:,<br />

aunque pue<strong>de</strong> darse el caso contrario.<br />

Los miembros <strong>de</strong> datos <strong>de</strong> una clase no pue<strong>de</strong>n ser inicializados don<strong>de</strong> son <strong>de</strong>clarados<br />

<strong>en</strong> el cuerpo <strong>de</strong> la clase. Deberán ser inicializados por el constructor <strong>de</strong> la clase, o las<br />

funciones ''set'' les podrán asignar valores.


La función con el mismo nombre que la clase, pero precedido por un carácter til<strong>de</strong> (~)<br />

se llama el <strong>de</strong>structor <strong>de</strong> dicha clase.<br />

Cuando una función miembro se <strong>de</strong>fine por fuera <strong>de</strong> la <strong>de</strong>finición <strong>de</strong> clase, el nombre<br />

<strong>de</strong> función es antecedido por el nombre <strong>de</strong> la clase y por el operador <strong>de</strong> resolución <strong>de</strong><br />

alcance binario (::). Dicha función miembro queda <strong>de</strong>ntro <strong>de</strong>l alcance <strong>de</strong> la clase.<br />

Ejemplo:<br />

void Punto :: setX (const int val) // Definimos el método setX<br />

// ámbito <strong>de</strong> la clase Punto.<br />

{<br />

_x = val;<br />

}<br />

void Punto :: setY (const int val)<br />

{<br />

_y = val;<br />

}<br />

El objeto apunto pue<strong>de</strong> usar estos métodos para establecer y para obt<strong>en</strong>er información<br />

sobre sí mismo:<br />

Punto apunto;<br />

apunto.setX(1); // Inicialización.<br />

apunto.setY(1);<br />

//<br />

// x es necesaria a partir <strong>de</strong> aquí, <strong>de</strong> modo que la <strong>de</strong>finimos aquí y la<br />

// inicializamos con el valor <strong>de</strong> la coor<strong>de</strong>nada _x <strong>de</strong> apunto.<br />

//<br />

int x = apunto.getX( );<br />

3.2. ALCANCE DE CLASE Y ACCESO A MIEMBROS DE CLASE<br />

Los nombres <strong>de</strong> variables y los <strong>de</strong> función <strong>de</strong>clarados <strong>en</strong> una <strong>de</strong>finición <strong>de</strong> clase, y los<br />

nombres <strong>de</strong> datos y funciones miembro <strong>de</strong> una clase, pert<strong>en</strong>ec<strong>en</strong> al alcance <strong>de</strong> dicha<br />

clase.<br />

D<strong>en</strong>tro <strong>de</strong>l alcance <strong>de</strong> clase, los miembros <strong>de</strong> clase son accesibles por todas las<br />

funciones miembro <strong>de</strong> dicha clase y pue<strong>de</strong>n ser refer<strong>en</strong>ciados sólo por su nombre. Fuera<br />

<strong>de</strong>l alcance <strong>de</strong> una clase, los miembros <strong>de</strong> clase se refer<strong>en</strong>cian, ya sea a través <strong>de</strong>l<br />

nombre <strong>de</strong>l objeto, una refer<strong>en</strong>cia a un objeto, o un apuntador a un objeto.


3.3. COMO CONTROLAR EL ACCESO A MIEMBROS<br />

Se pue<strong>de</strong> t<strong>en</strong>er acceso a los miembros <strong>de</strong> clase privado sólo por miembros (y amigos)<br />

<strong>de</strong> dicha clase. Se pue<strong>de</strong> t<strong>en</strong>er acceso a los miembros públicos <strong>de</strong> una clase mediante<br />

cualquier función <strong>de</strong>l programa.<br />

El cli<strong>en</strong>te <strong>de</strong> una clase pue<strong>de</strong> ser una función miembro <strong>de</strong> otra clase, o pue<strong>de</strong> ser una<br />

función global.<br />

Los miembros <strong>de</strong> clase públicos pres<strong>en</strong>tan una vista <strong>de</strong> los servicios que proporciona la<br />

clase.<br />

Para miembros <strong>de</strong> una clase, el acceso por omisión es privado.<br />

El acceso a los datos privados <strong>de</strong> una clase pue<strong>de</strong> ser controlado con cuidado mediante<br />

el uso <strong>de</strong> las funciones miembro conocidas como funciones <strong>de</strong> acceso. Si una clase<br />

<strong>de</strong>sea permitir que los cli<strong>en</strong>tes lean datos privados, la clase pue<strong>de</strong> proporcionar una<br />

función ''get''. Para permitir que los cli<strong>en</strong>tes modifiqu<strong>en</strong> datos privados, la clase pue<strong>de</strong><br />

proveer una función ''set''.<br />

Ejemplo:<br />

#inclu<strong>de</strong> <br />

// Definición <strong>de</strong> la clase Cfecha<br />

class Cfecha<br />

{<br />

public:<br />

// Constructor ( véase apdo. sigui<strong>en</strong>te)<br />

Cfecha( int dd = 1, int mm = 1, int aa = 1980 );<br />

// Funciones <strong>de</strong> acceso<br />

void get_fecha( int &, int &, int & );<br />

void set_fecha( int, int, int );<br />

private:<br />

int dia, mes, anyo; // Datos miembro<br />

};<br />

// Constructor<br />

Cfecha::Cfecha( int dd, int mm, int aa )<br />

{<br />

set_fecha( dd, mm, aa );<br />

}<br />

// Obt<strong>en</strong>er una fecha<br />

void Cfecha::get_fecha( int &dd, int &mm, int &aa )<br />

{<br />

dd = dia, mm = mes, aa = anyo;<br />

}


3.4. COMO INICIALIZAR OBJETOS DE CLASE : CONSTRUCTORES<br />

Los constructores son métodos que se usan para inicializar un objeto al mom<strong>en</strong>to <strong>de</strong> su<br />

<strong>de</strong>finición o para asignar almac<strong>en</strong>ami<strong>en</strong>to <strong>en</strong> memoria. Cuando se <strong>de</strong>clara un objeto <strong>de</strong><br />

una clase, se pue<strong>de</strong>n dar inicializadores <strong>en</strong> paréntesis a la <strong>de</strong>recha <strong>de</strong>l nombre <strong>de</strong>l objeto<br />

y antes <strong>de</strong>l punto y coma. Estos inicializadores son pasados como argum<strong>en</strong>tos al<br />

constructor <strong>de</strong> la clase.<br />

Los constructores pue<strong>de</strong>n t<strong>en</strong>er argum<strong>en</strong>tos por omisión.<br />

Si para una clase no se <strong>de</strong>fine ningún constructor, el compilador creará un constructor<br />

por omisión. Dicho constructor no ejecutará ninguna inicialización.<br />

Debemos incluir siempre un constructor que ejecute la inicialización a<strong>de</strong>cuada para su<br />

clase.<br />

Ejemplo:<br />

class Punto<br />

{<br />

int _x, _y;<br />

public :<br />

Punto( )<br />

{<br />

_x = _y = 0;<br />

}<br />

void SetX( const int val );<br />

void SetY( const int val );<br />

int getX { return _x; }<br />

int getY { return _y; }<br />

};<br />

Los constructores ti<strong>en</strong><strong>en</strong> el mismo nombre <strong>de</strong> la clase. No regresan ningún valor.<br />

Pue<strong>de</strong>n llevar argum<strong>en</strong>tos. Así:<br />

class Punto<br />

{<br />

int _x, _y;<br />

public:<br />

Punto()<br />

{<br />

_x = _y = 0;<br />

}


};<br />

// Continuamos con el ejemplo:<br />

Punto (const int x, const int y)<br />

{<br />

_x = x; // Para po<strong>de</strong>r inicializar un punto <strong>en</strong><br />

_y = y; // otras coor<strong>de</strong>nadas que no sean (0,0).<br />

}<br />

void setX (const int val);<br />

void setY (const int val);<br />

int getX() { return _x;}<br />

int getY() { return _y;}<br />

Los constructores son llamados implícitam<strong>en</strong>te cuando <strong>de</strong>finimos objetos <strong>de</strong> sus<br />

clases:<br />

Punto apunto;<br />

Punto bpunto(12,34);<br />

// Punto :: Punto()<br />

// Punto :: Punto(const int, const int)<br />

3.5. DESTRUCTORES<br />

Un <strong>de</strong>structor <strong>de</strong> clase es llamado automáticam<strong>en</strong>te cuando un objeto <strong>de</strong> una clase se<br />

sale <strong>de</strong> alcance: <strong>de</strong>bemos asegurarnos <strong>de</strong> que la memoria asignada sea liberada.<br />

Este método especial llamado <strong>de</strong>structor es llamado una vez por cada objeto <strong>en</strong> el<br />

mom<strong>en</strong>to <strong>de</strong> su <strong>de</strong>strucción.<br />

Un <strong>de</strong>structor no recibe parámetros ni regresa ningún valor. Una clase sólo pue<strong>de</strong> t<strong>en</strong>er<br />

un <strong>de</strong>structor: la homonimia <strong>de</strong> <strong>de</strong>structores no está permitida.<br />

La <strong>de</strong>strucción <strong>de</strong> los objetos ti<strong>en</strong>e lugar cuando el objeto abandona su ámbito <strong>de</strong><br />

<strong>de</strong>finición o es explícitam<strong>en</strong>te <strong>de</strong>struido. Esto último suce<strong>de</strong> cuando nosotros<br />

dinámicam<strong>en</strong>te asignamos un objeto y lo liberamos cuando ya no nos es necesario.<br />

Los <strong>de</strong>structores se <strong>de</strong>claran con el nombre <strong>de</strong> la clase prefijado con una til<strong>de</strong> ( ~ ):<br />

class Punto<br />

{<br />

int _x, _y;<br />

public:<br />

Punto()<br />

{<br />

_x = _y = 0;<br />

}


};<br />

// Continuamos con el ejemplo:<br />

Punto (const int x, const int y)<br />

{<br />

_x = xval;<br />

_y = yval;<br />

}<br />

Punto (const Punto &<strong>de</strong>s<strong>de</strong>)<br />

{<br />

_x = <strong>de</strong>s<strong>de</strong>._x;<br />

_y = <strong>de</strong>s<strong>de</strong>._y;<br />

}<br />

∼ Punto() { /* ¡Nada que hacer! */}<br />

void setX(const int val);<br />

void setY(const int val);<br />

int getX() {return _x;}<br />

int getY() {return _y;}<br />

3.6. CUANDO SON LLAMADOS LOS DESTRUCTORES Y CONSTRUCTORES<br />

Por lo regular, son llamados <strong>de</strong> forma automática. En g<strong>en</strong>eral, las llamadas <strong>de</strong><br />

<strong>de</strong>structor se efectúan <strong>en</strong> or<strong>de</strong>n inverso a las llamadas <strong>de</strong> constructor.<br />

3.7. ASIGNACIÓN POR OMISION EN COPIA A NIVEL DE MIEMBRO<br />

El operador <strong>de</strong> asignación ( = ) es utilizado para asignar un objeto a otro objeto <strong>de</strong>l<br />

mismo tipo.


4. CLASES<br />

4.1. OBJETOS CONSTANTES Y FUNCIONES MIEMBRO CONST<br />

La palabra reservada const indica que un objeto no es modificable. Para objetos const<br />

no se permit<strong>en</strong> llamadas <strong>de</strong> función miembro. Se pue<strong>de</strong>n <strong>de</strong>clarar funciones miembro<br />

const : sólo éstas pue<strong>de</strong>n operar sobre objetos const; estas funciones no pue<strong>de</strong>n<br />

modificar el objeto.<br />

Una función es <strong>de</strong>finida como const tanto <strong>en</strong> su <strong>de</strong>claración como <strong>en</strong> su <strong>de</strong>finición,<br />

insertando la palabra reservada const <strong>de</strong>spués <strong>de</strong> la lista <strong>de</strong> parámetros <strong>de</strong> la función, y,<br />

<strong>en</strong> el caso <strong>de</strong> la <strong>de</strong>finición <strong>de</strong> función, antes <strong>de</strong> la llave izquierda que inicia el cuerpo <strong>de</strong><br />

la función.<br />

Ejemplo:<br />

const Cfecha cumpleanyos;<br />

cumpleanyos.ok_fecha( );<br />

class Cfecha<br />

{<br />

public:<br />

// Funciones miembro <strong>de</strong> la clase<br />

//...<br />

int ok_fecha( ) const;<br />

//...<br />

};<br />

int Cfecha::ok_fecha( ) const<br />

{<br />

// Cuerpo <strong>de</strong> la función<br />

}<br />

Si una función miembro const se <strong>de</strong>fine fuera <strong>de</strong> la <strong>de</strong>finición <strong>de</strong> la clase, tanto la<br />

<strong>de</strong>claración como la <strong>de</strong>finición <strong>de</strong> la función miembro <strong>de</strong>berán incluir const.<br />

Una función miembro const pue<strong>de</strong> ser homónima <strong>en</strong> una versión no const.<br />

Para constructores y <strong>de</strong>structores <strong>de</strong> objetos const no se requiere la <strong>de</strong>claración const.<br />

A un constructor <strong>de</strong>be permitírsele po<strong>de</strong>r modificar un objeto <strong>de</strong> forma tal que el objeto<br />

pueda ser inicializado <strong>de</strong> forma correcta. Un <strong>de</strong>structor <strong>de</strong>be ser capaz <strong>de</strong> ejecutar sus<br />

trabajos <strong>de</strong> terminación, antes <strong>de</strong> que un objeto sea <strong>de</strong>struido.<br />

Un objeto const <strong>de</strong>be ser inicializado. Las asignaciones no son permitidas.


4.2. COMPOSICION: CLASES COMO MIEMBROS DE OTRAS CLASES<br />

Una clase pue<strong>de</strong> t<strong>en</strong>er otras clases como miembros.<br />

Cuando un objeto <strong>en</strong>tra <strong>en</strong> alcance, su constructor es llamado automáticam<strong>en</strong>te, por lo<br />

que es preciso especificar cómo se pasan argum<strong>en</strong>tos a constructores <strong>de</strong> objetos<br />

miembro. Se construy<strong>en</strong> los objetos miembro antes <strong>de</strong> que los objetos <strong>de</strong> clase que los<br />

incluy<strong>en</strong> sean construidos.<br />

4.3. FUNCIONES AMIGO Y CLASES AMIGO<br />

Po<strong>de</strong>mos <strong>de</strong>finir que funciones o clases sean amigos <strong>de</strong> una clase para permitirles<br />

acceso directo a sus miembros <strong>de</strong> datos privados. Se pue<strong>de</strong> <strong>de</strong>clarar una función o toda<br />

una clase como un fri<strong>en</strong>d <strong>de</strong> otra clase.<br />

Para <strong>de</strong>clarar una función como un fri<strong>en</strong>d <strong>de</strong> una clase, <strong>en</strong> la <strong>de</strong>finición <strong>de</strong> clase hay<br />

que prece<strong>de</strong>r el prototipo <strong>de</strong> función con la palabra reservada fri<strong>en</strong>d.<br />

Las <strong>de</strong>claraciones <strong>de</strong> amistad pue<strong>de</strong>n ser colocadas <strong>en</strong> cualquier parte <strong>de</strong> la <strong>de</strong>finición<br />

<strong>de</strong> clase.<br />

Es posible especificar funciones homónimas como amigos <strong>de</strong> una clase. Cada función<br />

homónima que se <strong>de</strong>sea como un amigo, <strong>de</strong>be ser <strong>de</strong>clarada <strong>en</strong> forma explícita <strong>en</strong> la<br />

<strong>de</strong>finición <strong>de</strong> clase como amigo <strong>de</strong> la clase.<br />

Ejemplo:<br />

class Complejo<br />

{<br />

...<br />

public:<br />

...<br />

fri<strong>en</strong>d Complejo operator +<br />

(<br />

const Complejo &,<br />

const Complejo &<br />

);<br />

}<br />

Complejo operator +(const Complejo &op1, const Complejo &op2)<br />

{<br />

double real = op1._real + op2._real,<br />

imag = op1._imag + op2._imag;<br />

}<br />

return ( Complejo (real, imag));


No se <strong>de</strong>b<strong>en</strong> usar amigos muy seguido <strong>de</strong>bido a que romp<strong>en</strong> con el principio <strong>de</strong><br />

aislami<strong>en</strong>to <strong>de</strong> datos <strong>en</strong> sus fundam<strong>en</strong>tos. Si los usamos <strong>de</strong> forma muy seguida, es señal<br />

<strong>de</strong> que t<strong>en</strong>emos que modificar nuestra gráfica <strong>de</strong> her<strong>en</strong>cia.<br />

4.4. COMO UTILIZAR UN APUNTADOR THIS<br />

Cada objeto manti<strong>en</strong>e un apuntador a sí mismo llamado apuntador this que es un<br />

argum<strong>en</strong>to implícito <strong>en</strong> todas las refer<strong>en</strong>cias a miembros incluidos <strong>de</strong>ntro <strong>de</strong> dicho<br />

objeto. El apuntador this pue<strong>de</strong> también ser utilizado <strong>de</strong> forma explícita. Mediante el<br />

uso <strong>de</strong> la palabra reservada this, cada objeto pue<strong>de</strong> <strong>de</strong>terminar su propia dirección.<br />

El apuntador this es utilizado <strong>de</strong> manera implícita para refer<strong>en</strong>ciar tanto los miembros<br />

<strong>de</strong> datos como las funciones miembro <strong>de</strong> un objeto. El tipo <strong>de</strong> este apuntador this<br />

<strong>de</strong>p<strong>en</strong><strong>de</strong> <strong>de</strong>l tipo <strong>de</strong>l objeto y <strong>de</strong> si es <strong>de</strong>clarada const la función miembro <strong>en</strong> la cual this<br />

es utilizado.<br />

Un uso <strong>de</strong>l apuntador this es impedir que un objeto sea asignado a sí mismo.<br />

Ejemplo:<br />

// Declaramos un objeto fecha1 y a continuación le <strong>en</strong>viamos el<br />

// m<strong>en</strong>saje set_fecha.<br />

fecha1.set_fecha( );<br />

// <strong>C++</strong> <strong>de</strong>fine el puntero this para apuntar al objeto fecha1 <strong>de</strong> la<br />

// forma:<br />

Cfecha *const this = &fecha1;<br />

// La función set_fecha pue<strong>de</strong> ser <strong>de</strong>finida también <strong>de</strong> la sigui<strong>en</strong>te<br />

// forma:<br />

void Cfecha::set_fecha( )<br />

{<br />

cout > this->dia;<br />

cout > this->mes;<br />

cout > this->anyo;<br />

}


4.5. ASIGNACION DINAMICA DE MEMORIA MEDIANTE NEW Y DELETE<br />

Los operadores new y <strong>de</strong>lete ofrec<strong>en</strong> una mejor forma <strong>de</strong> efectuar la asignación<br />

dinámica <strong>de</strong> memoria, que mediante las llamadas <strong>de</strong> función malloc y free <strong>de</strong> C.<br />

El operador new crea <strong>en</strong> forma automática un objeto <strong>de</strong>l tamaño apropiado, llama el<br />

constructor para el objeto (si hay uno disponible) y regresa un apuntador <strong>de</strong>l tipo<br />

correcto. Si new no pue<strong>de</strong> <strong>en</strong>contrar espacio, regresa un apuntador 0.<br />

char *ptr;<br />

ptr = new char[longitud];<br />

Mediante el operador <strong>de</strong>lete liberamos espacio para ese objeto:<br />

<strong>de</strong>lete ptr;<br />

<strong>C++</strong> permite incluir un inicializador para un objeto recién creado.<br />

New invoca al constructor <strong>de</strong> manera automática, y <strong>de</strong>lete automáticam<strong>en</strong>te invoca al<br />

<strong>de</strong>structor <strong>de</strong> la clase.<br />

4.6. MIEMBROS DE CLASE ESTATICOS<br />

Un miembro <strong>de</strong> datos estático repres<strong>en</strong>ta información ''aplicable a toda la clase''. La<br />

<strong>de</strong>claración <strong>de</strong> un miembro estático empieza con la palabra reservada static.<br />

Estos miembros <strong>de</strong> datos estáticos ti<strong>en</strong><strong>en</strong> alcance <strong>de</strong> clase. Pue<strong>de</strong>n ser públicos,<br />

privados o protegidos.<br />

Una función miembro pue<strong>de</strong> ser <strong>de</strong>clarada static si no ti<strong>en</strong>e acceso a miembros <strong>de</strong><br />

clase no estáticos. A difer<strong>en</strong>cia <strong>de</strong> las funciones miembro no estáticas, una función<br />

miembro estática no ti<strong>en</strong>e apuntador this.<br />

Los miembros estáticos <strong>de</strong> una clase son accesibles a través <strong>de</strong> un objeto <strong>de</strong> dicha<br />

clase, o pue<strong>de</strong>n ser accesibles a través <strong>de</strong>l nombre <strong>de</strong> la clase mediante el uso <strong>de</strong>l<br />

operador <strong>de</strong> resolución <strong>de</strong> alcance.<br />

4.7. CLASES CONTENEDOR E ITERADORES<br />

Las clases cont<strong>en</strong>edor (o clases colección) están diseñadas para cont<strong>en</strong>er colecciones<br />

<strong>de</strong> objetos, como puedan ser arreglos y listas <strong>en</strong>lazadas.<br />

Asociamos iteradores con la clase <strong>de</strong> colección. Un iterador es un objeto que regresa<br />

el sigui<strong>en</strong>te elem<strong>en</strong>to <strong>de</strong> una colección. Una clase cont<strong>en</strong>edor pue<strong>de</strong> t<strong>en</strong>er varios<br />

iteradores operando sobre ella simultáneam<strong>en</strong>te.


El recorrido <strong>de</strong> una estructura <strong>de</strong> datos es implem<strong>en</strong>tado usando iteradores. Estos<br />

garantizan la visita a cada ítem <strong>de</strong> su estructura <strong>de</strong> datos asociada <strong>en</strong> un or<strong>de</strong>n bi<strong>en</strong><br />

<strong>de</strong>finido. Deb<strong>en</strong> proveer al m<strong>en</strong>os las sigui<strong>en</strong>tes propieda<strong>de</strong>s:<br />

1. Elem<strong>en</strong>to actual. El iterador visita los elem<strong>en</strong>tos <strong>de</strong> datos uno a la vez. El<br />

elem<strong>en</strong>to que se visita actualm<strong>en</strong>te es llamado el ''elem<strong>en</strong>to actual''.<br />

2. Función sucesor. La ejecución <strong>de</strong>l paso al sigui<strong>en</strong>te elem<strong>en</strong>to <strong>de</strong> datos <strong>de</strong>p<strong>en</strong><strong>de</strong> <strong>de</strong><br />

la estrategia <strong>de</strong> recorrido implem<strong>en</strong>tada por el iterador. La función sucesor se usa<br />

para regresar el elem<strong>en</strong>to que será visitado <strong>en</strong>seguida: regresa el sucesor <strong>de</strong>l<br />

elem<strong>en</strong>to actual.<br />

3. Condición <strong>de</strong> terminación. El iterador <strong>de</strong>be proveer un mecanismo que chequee si<br />

se han visitado todos los elem<strong>en</strong>tos, o si falta alguno por visitar.<br />

4.8. CLASES PLANTILLA<br />

En <strong>C++</strong>, los tipos <strong>de</strong> datos g<strong>en</strong>éricos son llamados plantillas <strong>de</strong> clase o simplem<strong>en</strong>te<br />

plantillas (templates). Una plantilla <strong>de</strong> clase se parece a la <strong>de</strong>finición <strong>de</strong> una clase<br />

normal, <strong>en</strong> la que algunos aspectos son repres<strong>en</strong>tados por sustitutos (placehol<strong>de</strong>rs).<br />

Las <strong>de</strong>finiciones <strong>de</strong> clases plantilla empiezan con la línea:<br />

template <br />

<strong>en</strong> la línea que antece<strong>de</strong> a la <strong>de</strong>finición <strong>de</strong> clase. Pue<strong>de</strong> existir más <strong>de</strong> un tipo<br />

parametrizado. Si es así, estarán separados por comas y cada tipo estará precedido por la<br />

palabra reservada class. ( Ver apdo. 2.11., pág. 20).<br />

Luego, con la palabra clave template se inician todas las <strong>de</strong>claraciones <strong>de</strong> plantillas.<br />

Los argum<strong>en</strong>tos <strong>de</strong> una plantilla se <strong>en</strong>cierran <strong>en</strong> corchetes angulares.<br />

Cada argum<strong>en</strong>to especifica un sustituto <strong>en</strong> la sigui<strong>en</strong>te <strong>de</strong>finición <strong>de</strong> clase.<br />

Ejemplo:<br />

template // T es el sustituto<br />

Class Lista: ...<br />

{<br />

public:<br />

...<br />

void apéndice( const T dato);<br />

...<br />

};


Una clase plantilla se produce especificando el tipo <strong>de</strong> la clase que sigue al nombre <strong>de</strong> la<br />

clase:<br />

NombreClase NombreObjeto;<br />

Ejemplo :<br />

Lista listaDeEnteros<br />

4.9. CLASES ABSTRACTAS<br />

Exist<strong>en</strong> muchas situaciones <strong>en</strong> las cuales resulta útil <strong>de</strong>finir clases para las cuales el<br />

programador no ti<strong>en</strong>e int<strong>en</strong>ción <strong>de</strong> producir ningún objeto. Estas clases se conoc<strong>en</strong><br />

como clases abstractas. A partir <strong>de</strong> una clase base abstracta no se pue<strong>de</strong>n producir<br />

objetos.<br />

El único fin <strong>de</strong> una clase abstracta es proporcionar una clase base apropiada, a partir <strong>de</strong><br />

la cual las clases pue<strong>de</strong>n heredar interfaz y/o puesta <strong>en</strong> práctica. Las clases a partir <strong>de</strong><br />

las cuales los objetos se pue<strong>de</strong>n producir, se conoc<strong>en</strong> como clases concretas.<br />

Se <strong>de</strong>fin<strong>en</strong> igual que las clases ordinarias. Sin embargo, algunos <strong>de</strong> sus métodos están<br />

<strong>de</strong>signados para ser <strong>de</strong>finidos necesariam<strong>en</strong>te por sus subclases. Sólo m<strong>en</strong>cionamos su<br />

signature (nombre <strong>de</strong>l método más sus argum<strong>en</strong>tos) incluy<strong>en</strong>do el tipo que regresa, pero<br />

no una <strong>de</strong>finición. Se podría <strong>de</strong>cir que omitimos el cuerpo <strong>de</strong>l método. Esto se expresa<br />

añadi<strong>en</strong>do ''=0'' <strong>de</strong>spués <strong>de</strong> las ''signatures'' <strong>de</strong> los métodos:<br />

class ObjetoDesplegable<br />

{<br />

...<br />

public:<br />

...<br />

virtual void print( ) = 0;<br />

};<br />

Estas <strong>de</strong>claraciones <strong>de</strong> métodos son también llamadas métodos puros. También <strong>de</strong>b<strong>en</strong><br />

ser <strong>de</strong>clarados virtuales, <strong>de</strong>bido a que sólo queremos usar objetos <strong>de</strong> clases <strong>de</strong>rivadas.<br />

Las clases que <strong>de</strong>fin<strong>en</strong> métodos puros son llamadas clases abstractas.


5. HOMONIMIA DE OPERADORES<br />

5.1. FUNDAMENTOS DE LA HOMONIMIA DE OPERADORES<br />

<strong>C++</strong> permite sobrecargar casi todos sus operadores por tipos recién creados.<br />

Se hace la homonimia <strong>de</strong> operadores escribi<strong>en</strong>do una <strong>de</strong>finición <strong>de</strong> función (con<br />

<strong>en</strong>cabezado y cuerpo) como se haría normalm<strong>en</strong>te, excepto que ahora el nombre <strong>de</strong> la<br />

función se convierte <strong>en</strong> la palabra clave operator, seguida por el símbolo<br />

correspondi<strong>en</strong>te al operador homónimo:<br />

operator (,)<br />

{<br />

<br />

}<br />

Para utilizar un operador sobre objetos <strong>de</strong> clase, dicho operador <strong>de</strong>berá ser un<br />

homónimo con dos excepciones. El operador <strong>de</strong> asignación ( = ) pue<strong>de</strong> ser utilizado sin<br />

homónimo con cualquier clase. El operador <strong>de</strong> dirección ( & ) también pue<strong>de</strong> ser<br />

utilizado sin homonimia con objetos <strong>de</strong> cualquier clase.<br />

La homonimia <strong>de</strong> operadores no es automática; para llevar a cabo las operaciones<br />

<strong>de</strong>seadas, el programador <strong>de</strong>berá escribir funciones <strong>de</strong> homonimia <strong>de</strong> operadores.<br />

5.2. RESTRICCIONES SOBRE LA HOMONIMIA DE OPERADORES<br />

Se pue<strong>de</strong> hacer la homonimia <strong>de</strong> la mayor parte <strong>de</strong> los operadores <strong>de</strong> <strong>C++</strong>:<br />

Operadores que pue<strong>de</strong>n t<strong>en</strong>er homónimos<br />

+ - * / % ^ & |<br />

∼ ! = < > += -= *=<br />

/= %= ^= &= |= > >>=<br />


No es posible modificar el número <strong>de</strong> operandos que toma un operador. Tampoco se<br />

pue<strong>de</strong>n crear operadores nuevos; sólo se pue<strong>de</strong> hacer la homonimia <strong>de</strong> operadores<br />

exist<strong>en</strong>tes.<br />

La homonimia <strong>de</strong> operador funciona sólo con objetos <strong>de</strong> tipos <strong>de</strong>finidos por el usuario<br />

o por una combinación <strong>de</strong> un objeto <strong>de</strong> tipo <strong>de</strong>finido por el usuario y un objeto <strong>de</strong> tipo<br />

incorporado.<br />

5.3. HOMONIMIA DE OPERADORES DE INSERCION Y DE EXTRACCION DE<br />

FLUJO<br />

Se hace la homonimia <strong>de</strong> estos operadores ( ) para procesar cada tipo <strong>de</strong> datos<br />

estándar, incluy<strong>en</strong>do ca<strong>de</strong>nas y direcciones <strong>de</strong> memoria; también para ejecutar <strong>en</strong>tradas<br />

y salidas para tipos <strong>de</strong>finidos por usuario.<br />

Los operadores <strong>de</strong> <strong>en</strong>trada y <strong>de</strong> salida homónimos <strong>de</strong>b<strong>en</strong> ser <strong>de</strong>clarados como amigo,<br />

si han <strong>de</strong> t<strong>en</strong>er acceso directo a los miembros <strong>de</strong> clase no públicos.<br />

5.4. HOMONIMIA DE OPERADORES UNARIOS<br />

Se pue<strong>de</strong> hacer la homonimia <strong>de</strong> un operador unario para una clase como función<br />

miembro no estática sin argum<strong>en</strong>tos, o como función no miembro con un argum<strong>en</strong>to;<br />

dicho argum<strong>en</strong>to <strong>de</strong>be ser un objeto <strong>de</strong> la clase o una refer<strong>en</strong>cia a un objeto <strong>de</strong> la clase.<br />

5.5. HOMONIMIA DE OPERADORES BINARIOS<br />

Se pue<strong>de</strong> hacer la homonimia <strong>de</strong> un operador binario como función miembro no<br />

estática con un argum<strong>en</strong>to o como función no miembro con dos argum<strong>en</strong>tos ( uno <strong>de</strong><br />

dichos argum<strong>en</strong>tos <strong>de</strong>bi<strong>en</strong>do ser un objeto <strong>de</strong> clase o una refer<strong>en</strong>cia a un objeto <strong>de</strong><br />

clase).<br />

Así, por ejemplo, podríamos <strong>de</strong>finir un operador ''+'' <strong>de</strong> la sigui<strong>en</strong>te forma:<br />

Class Complejo<br />

{<br />

...<br />

public :<br />

...<br />

Complejo operator + ( const Complejo &op)<br />

{<br />

double real = _real + op._real,<br />

imag = _imag + op._imag;<br />

};<br />

}<br />

...<br />

return<br />

(Complejo ( real, imag));


En este caso, se ha hecho <strong>de</strong>l + un miembro <strong>de</strong> la clase Complejo. Así, una expresión<br />

<strong>de</strong> la forma:<br />

c = a + b;<br />

es traducida a una llamada a método :<br />

c = a.operator +(b);<br />

Así, el operador binario + sólo necesita un argum<strong>en</strong>to. El primer argum<strong>en</strong>to es provisto<br />

implícitam<strong>en</strong>te por el objeto invocante (<strong>en</strong> este caso a).<br />

5.6. ESTUDIO DE CASO : UNA CLASE ARRAY<br />

La clase permite que, mediante el operador <strong>de</strong> asignación, un objeto <strong>de</strong> arreglo sea<br />

asignado a otro. Al pasar el arreglo a una función, su tamaño no necesita ser pasado<br />

como argum<strong>en</strong>to. Mediante los operadores <strong>de</strong> extracción y <strong>de</strong> inserción <strong>de</strong> flujo,<br />

respectivam<strong>en</strong>te, es posible introducir o extraer arreglos completos. Se pue<strong>de</strong>n comparar<br />

arreglos utilizando los operadores <strong>de</strong> igualdad == y !=.<br />

En una <strong>de</strong>claración se llama al constructor <strong>de</strong> copia cuando un objeto <strong>de</strong> la clase Array<br />

es producido e inicializado con otro objeto <strong>de</strong> la clase Array.<br />

Para evitar que un objeto <strong>de</strong> clase sea asignado a otro, <strong>de</strong>bemos <strong>de</strong>finir el operador <strong>de</strong><br />

asignación como miembro privado <strong>de</strong> la clase.<br />

5.7. CONVERSION ENTRE TIPOS<br />

El compilador no sabe <strong>de</strong> forma automática cómo convertir <strong>en</strong>tre tipos <strong>de</strong>finidos por<br />

usuario y tipos incorporados. El programador <strong>de</strong>berá especificar <strong>en</strong> forma explícita<br />

cómo <strong>de</strong>berán ocurrir dichas conversiones. Estas conversiones pue<strong>de</strong>n ser ejecutadas<br />

mediante constructores <strong>de</strong> conversión: constructores <strong>de</strong> un solo argum<strong>en</strong>to, que sólo<br />

conviertan objetos <strong>de</strong> otros tipos <strong>en</strong> objetos <strong>de</strong> una clase particular.<br />

Un operador <strong>de</strong> conversión ( operador <strong>de</strong> conversión explícita cast ) pue<strong>de</strong> ser<br />

utilizado para convertir un objeto <strong>de</strong> una clase <strong>en</strong> un objeto <strong>de</strong> otra clase o <strong>en</strong> un objeto<br />

<strong>de</strong> un tipo incorporado. Este operador no pue<strong>de</strong> ser una función amigo; <strong>de</strong>be ser una<br />

función miembro no estática.<br />

En <strong>C++</strong>, una construcción cast pue<strong>de</strong> expresarse <strong>de</strong> la forma sigui<strong>en</strong>te:<br />

Ejemplos:<br />

nombre-<strong>de</strong>-tipo(expresión)<br />

sqrt (double(n+2))<br />

int *p = ( int * ) 0x1F5;<br />

Notación funcional:<br />

type<strong>de</strong>f int * pint;<br />

int *p = pint( 0x1F5 );


6. HERENCIA<br />

La her<strong>en</strong>cia es una forma <strong>de</strong> reutilización <strong>de</strong>l software, <strong>en</strong> la cual se crean clases<br />

nuevas a partir <strong>de</strong> clases exist<strong>en</strong>tes, mediante la absorción <strong>de</strong> sus atributos y<br />

comportami<strong>en</strong>tos, y embelleci<strong>en</strong>do éstos con las capacida<strong>de</strong>s que las clases nuevas<br />

requier<strong>en</strong>.<br />

Al crear una clase nueva, <strong>en</strong> vez <strong>de</strong> escribir <strong>en</strong> su totalidad miembros <strong>de</strong> datos y<br />

funciones miembro nuevos, el programador pue<strong>de</strong> <strong>de</strong>terminar que la clase nueva <strong>de</strong>be<br />

heredar los miembros <strong>de</strong> datos y las funciones miembro prov<strong>en</strong>i<strong>en</strong>tes <strong>de</strong> una clase base<br />

ya <strong>de</strong>finida. La clase nueva se conoce como clase <strong>de</strong>rivada.<br />

La her<strong>en</strong>cia forma estructuras jerárquicas <strong>de</strong> apari<strong>en</strong>cia arboresc<strong>en</strong>te. Una clase base<br />

existe <strong>en</strong> una relación jerárquica con sus clases <strong>de</strong>rivadas.<br />

Mediante la her<strong>en</strong>cia única, una clase es <strong>de</strong>rivada <strong>de</strong> una única clase base. Con la<br />

her<strong>en</strong>cia múltiple una clase <strong>de</strong>rivada hereda <strong>de</strong> múltiples clases base.<br />

En <strong>C++</strong>, ''hereda <strong>de</strong>'' se reemplaza por dos puntos ( : ). Luego, la sintaxis para escribir<br />

una clase <strong>de</strong>rivada es:<br />

Ejemplo:<br />

class tipo_clase_<strong>de</strong>rivada: (public/private/protected) tipo_clase_base { };<br />

class Puntos3D : public Punto<br />

{<br />

int _z;<br />

public:<br />

Puntos3D ( )<br />

{<br />

setX(0);<br />

setY(0);<br />

_z = 0;<br />

}<br />

Puntos3D (const int x, const int y, const int z)<br />

{<br />

setX(x);<br />

setY(y);<br />

_z = z;<br />

}<br />

∼ Puntos3D( ) { /* Nada que hacer */}<br />

int getZ( ) { return _z;}<br />

void setZ ( const int val) { _z = val;}<br />

};


6.1. TIPOS DE HERENCIA<br />

<strong>C++</strong> distingue dos tipos <strong>de</strong> her<strong>en</strong>cia : pública y privada. Por <strong>de</strong>fecto, las clases se<br />

<strong>de</strong>rivan unas <strong>de</strong> otras <strong>en</strong> forma privada. Si queremos her<strong>en</strong>cia pública, <strong>de</strong>bemos<br />

<strong>de</strong>círselo explícitam<strong>en</strong>te al compilador.<br />

El tipo <strong>de</strong> her<strong>en</strong>cia influye sobre los privilegios <strong>de</strong> acceso a elem<strong>en</strong>tos <strong>de</strong> las diversas<br />

superclases.<br />

Los miembros públicos <strong>de</strong> una clase base son accesibles a todas las funciones <strong>en</strong> el<br />

programa. Los miembros privados <strong>de</strong> clase base son accesibles sólo para las funciones<br />

miembro y los amigos <strong>de</strong> la clase base.<br />

El tipo protected se usa para elem<strong>en</strong>tos que <strong>de</strong>berían ser usados directam<strong>en</strong>te <strong>en</strong> las<br />

subclases, pero que no <strong>de</strong>berían estar accesibles <strong>de</strong>s<strong>de</strong> fuera. Luego, el acceso protegido<br />

sirve como nivel intermedio <strong>de</strong> protección <strong>en</strong>tre el acceso público y el privado. Los<br />

miembros protegidos <strong>de</strong> clase base son accesibles sólo por miembros y amigos <strong>de</strong> la<br />

clase base, y por miembros y amigos <strong>de</strong> las clases <strong>de</strong>rivadas.<br />

Los miembros <strong>de</strong> clases <strong>de</strong>rivadas pue<strong>de</strong>n hacer refer<strong>en</strong>cia a miembros públicos y<br />

protegidos <strong>de</strong> la clase base sólo utilizando los nombres <strong>de</strong> los miembros.<br />

6.2. CLASES BASE PUBLICAS, PROTEGIDAS Y PRIVADAS<br />

Al <strong>de</strong>rivar una clase a partir <strong>de</strong> una clase base, la clase base pue<strong>de</strong> ser heredada como<br />

public, protected o private.<br />

Al <strong>de</strong>rivar una clase a partir <strong>de</strong> una clase base pública, los miembros públicos <strong>de</strong> la<br />

base se conviert<strong>en</strong> <strong>en</strong> miembros públicos <strong>de</strong> la clase <strong>de</strong>rivada, y los miembros<br />

protegidos <strong>de</strong> la clase base se conviert<strong>en</strong> <strong>en</strong> miembros protegidos <strong>de</strong> la clase <strong>de</strong>rivada.<br />

Los miembros privados <strong>de</strong> una clase base nunca son accesibles <strong>en</strong> forma directa <strong>de</strong>s<strong>de</strong><br />

una clase <strong>de</strong>rivada.<br />

Al <strong>de</strong>rivar una clase a partir <strong>de</strong> una clase base protegida, los miembros públicos y<br />

protegidos <strong>de</strong> la clase base se conviert<strong>en</strong> <strong>en</strong> miembros protegidos <strong>de</strong> la clase <strong>de</strong>rivada.<br />

Cuando se <strong>de</strong>riva una clase a partir <strong>de</strong> una clase base privada, los miembros públicos y<br />

protegidos <strong>de</strong> la clase base se conviert<strong>en</strong> <strong>en</strong> miembros privados <strong>de</strong> la clase <strong>de</strong>rivada.<br />

ESPECIFICADO<br />

R DE ACCESO<br />

ACCESIBLE<br />

DESDE SU<br />

PROPIA CLASE<br />

ACCESIBLE<br />

DESDE CLASE<br />

DERIVADA<br />

ACCESIBLE DESDE<br />

OBJETOS FUERA<br />

DE LA CLASE<br />

public si si si<br />

protected si si no<br />

private si no no


6.3. CONSTRUCCION Y DESTRUCCION<br />

En g<strong>en</strong>eral, anterior a la ejecución <strong>de</strong>l cuerpo particular <strong>de</strong>l constructor, los<br />

constructores <strong>de</strong> cada superclase son llamados para inicializar su parte <strong>de</strong>l objeto<br />

creado. Así, al constructor <strong>de</strong> clase <strong>de</strong>rivada siempre llamará primero al constructor <strong>de</strong><br />

su clase base, a fin <strong>de</strong> crear y <strong>de</strong> inicializar los miembros <strong>de</strong> la clase base <strong>de</strong> la clase<br />

<strong>de</strong>rivada.<br />

Po<strong>de</strong>mos especificar los constructores <strong>de</strong>seados <strong>de</strong>spués <strong>de</strong> un signo <strong>de</strong> dos puntos (:).<br />

Ejemplo:<br />

class Puntos3D : public Punto<br />

{<br />

...<br />

public:<br />

Puntos3D ( ) {...}<br />

Puntos3D (<br />

const int x,<br />

const int y,<br />

const int z) : Punto (x,y)<br />

{<br />

_z = z;<br />

}<br />

...<br />

};<br />

Si hay más superclases, proveemos sus llamadas a constructor como una lista separada<br />

por comas. Este mecanismo se usa también para crear objetos cont<strong>en</strong>idos.<br />

La inicialización dinámica pue<strong>de</strong> ser usada con tipos <strong>de</strong> datos integrados. Por ejemplo:<br />

Punto ( ): _x(0), _y(0) { }<br />

Punto ( const int x, const int y) : _x(x), _y(y) { }<br />

Los <strong>de</strong>structores serán llamados <strong>en</strong> or<strong>de</strong>n inverso a las llamadas <strong>de</strong> constructor, por lo<br />

que un <strong>de</strong>structor <strong>de</strong> clase <strong>de</strong>rivada será llamado antes <strong>de</strong>l <strong>de</strong>structor <strong>de</strong> su clase base ( o<br />

superclase). ( Ver apdo. 3.5., pág. 25 ).<br />

6.4. HERENCIA MULTIPLE :<br />

La her<strong>en</strong>cia múltiple significa que una clase <strong>de</strong>rivada (subclase) hereda los miembros<br />

<strong>de</strong> varias superclases.<br />

Sintaxis:<br />

class tipo_base_<strong>de</strong>rivada: (public/private/protected)tipo_clase_base1,<br />

(public/private/protected)tipo_clase_base2 { };


7. POLIMORFISMO<br />

Es la capacidad <strong>de</strong> objetos <strong>de</strong> clases distintas, relacionados mediante la her<strong>en</strong>cia, a<br />

respon<strong>de</strong>r <strong>de</strong> forma difer<strong>en</strong>te a una misma llamada <strong>de</strong> función miembro. En <strong>C++</strong>, el<br />

polimorfismo se realiza por uno <strong>de</strong> los métodos sigui<strong>en</strong>tes: sobrecarga <strong>de</strong> operadores o<br />

funciones virtuales.<br />

Po<strong>de</strong>mos <strong>de</strong>clarar que los métodos <strong>de</strong> las clases sean virtual con el fin <strong>de</strong> forzar que<br />

su evaluación se base <strong>en</strong> el cont<strong>en</strong>ido <strong>de</strong> los objetos más que <strong>en</strong> su tipo. Con el uso <strong>de</strong><br />

esta palabra clave, una función pue<strong>de</strong> estar <strong>de</strong>finida <strong>en</strong> una clase base y <strong>en</strong> su clase<br />

<strong>de</strong>rivada bajo el mismo nombre. La función no <strong>de</strong>berá ser <strong>de</strong>clarada virtual más que <strong>en</strong><br />

la clase base:<br />

class ObjetoDesplegable<br />

{<br />

public:<br />

virtual void print( );<br />

};<br />

La clase ObjetoDesplegable <strong>de</strong>fine un método print( ), el cual es virtual. De esta clase<br />

po<strong>de</strong>mos <strong>de</strong>rivar otras clases:<br />

class Punto: public ObjetoDesplegable<br />

{<br />

...<br />

public:<br />

...<br />

void print( ) { ... }<br />

};<br />

Nuevam<strong>en</strong>te, print( ) es un método virtual <strong>de</strong>bido a que hereda esta propiedad <strong>de</strong><br />

ObjetoDesplegable. La función display( ), que es capaz <strong>de</strong> dibujar cualquier tipo <strong>de</strong><br />

objeto <strong>de</strong>splegable, pue<strong>de</strong> por tanto ser <strong>de</strong>finida como:<br />

void display ( const ObjetoDesplegable &obj)<br />

{<br />

obj.print ( );<br />

};<br />

Cuando se usan métodos virtuales, el <strong>de</strong>structor <strong>de</strong> la clase correspondi<strong>en</strong>te <strong>de</strong>be ser<br />

<strong>de</strong>clarado también virtual cuando se usan apuntadores a subclases (virtuales) cuando<br />

llega el mom<strong>en</strong>to <strong>de</strong> <strong>de</strong>struirlas. Debido a que el apuntador está <strong>de</strong>clarado como<br />

superclase, su <strong>de</strong>structor normalm<strong>en</strong>te sería llamado.


8. PLANTILLAS PARA LOS NODOS<br />

El nodo es el bloque <strong>básico</strong> <strong>de</strong> construcción <strong>de</strong> una lista. Un nodo no ti<strong>en</strong>e nada más<br />

que un apuntador a otro nodo.<br />

Declaración <strong>de</strong> la clase Nodo:<br />

class Nodo<br />

{<br />

Nodo *_<strong>de</strong>recha; // Asumimos que este nodo vecino siempre<br />

// está <strong>de</strong>l lado <strong>de</strong>recho.<br />

public :<br />

Nodo ( Nodo *<strong>de</strong>recha = NULL) : _<strong>de</strong>recha ( <strong>de</strong>recha) { }<br />

Nodo ( const Nodo &val) : _<strong>de</strong>recha ( val._<strong>de</strong>recha) { }<br />

// Const justo antes <strong>de</strong>l cuerpo <strong>de</strong>l método: <strong>de</strong>clara constante al método<br />

// <strong>en</strong> lo que respecta a los elem<strong>en</strong>tos <strong>de</strong>l objeto invocante. Sólo se pue<strong>de</strong><br />

// usar este mecanismo <strong>en</strong> <strong>de</strong>claraciones <strong>de</strong> métodos o <strong>de</strong>finiciones.<br />

};<br />

const Nodo *<strong>de</strong>recha ( ) const { return _<strong>de</strong>recha;}<br />

Nodo *&<strong>de</strong>recha( ) {return _<strong>de</strong>recha;}<br />

Nodo &operator = ( const Nodo &val)<br />

{<br />

_<strong>de</strong>recha = val._<strong>de</strong>recha;<br />

return *this;<br />

}<br />

const int operator == ( const Nodo &val) const {<br />

return _<strong>de</strong>recha == val._<strong>de</strong>recha;<br />

}<br />

const int operator != ( const Nodo &val) const {<br />

return ! ( *this == val);<br />

}<br />

Cuando usamos un const justo antes <strong>de</strong>l cuerpo <strong>de</strong>l método (como ocurre <strong>en</strong><br />

<strong>de</strong>recha()), const <strong>de</strong>clara al método constante <strong>en</strong> lo que respecta a los elem<strong>en</strong>tos <strong>de</strong>l<br />

objeto invocante. Sólo está permitido usar este mecanismo <strong>en</strong> <strong>de</strong>claraciones <strong>de</strong> métodos<br />

o <strong>de</strong>finiciones, respectivam<strong>en</strong>te.<br />

Este tipo <strong>de</strong> modificador const también se usa para checar sobrecarga. Así:


class Arboles<br />

{<br />

...<br />

int arboles( ) const;<br />

int arboles( );<br />

};<br />

En el ejemplo anterior, el modificador const <strong>de</strong>clara dos métodos distintos. El primero<br />

se usa <strong>en</strong> contextos constantes y el segundo <strong>en</strong> contextos variables.<br />

This apunta al objeto invocador.<br />

Las aplicaciones reales requier<strong>en</strong> que los nodos llev<strong>en</strong> datos. Esto significa<br />

especializar los nodos. Los datos pue<strong>de</strong>n ser <strong>de</strong> cualquier tipo; usamos la construcción<br />

<strong>de</strong> plantilla:<br />

template <br />

class DatoNodo : public Nodo<br />

// La plantilla DatoNodo especializa la clase Nodo para que transporte da-<br />

// tos <strong>de</strong> cualquier tipo. Aña<strong>de</strong> funcionalidad para accesar su elem<strong>en</strong>to <strong>de</strong><br />

// datos y también ofrece el mismo conjunto <strong>de</strong> funcionalidad estándar:<br />

// Copy Constructor, operator = ( ) y operator = = ( ).<br />

{<br />

T _data;<br />

public :<br />

DatoNodo ( const T dato, DatoNodo *<strong>de</strong>recha = NULL) :<br />

Nodo ( <strong>de</strong>recha ), _dato ( dato) { }<br />

DatoNodo ( const DatoNodo &val) :<br />

Nodo ( val), _dato ( val._dato) { }<br />

const DatoNodo *<strong>de</strong>recha ( ) const {<br />

return ((DatoNodo *) Nodo :: <strong>de</strong>recha( ) );<br />

}<br />

DatoNodo *&<strong>de</strong>recha( ) {return ((DatoNodo *&) Nodo :: <strong>de</strong>recha( ) );}<br />

const T &dato( ) const { return _dato ;}<br />

T &dato ( ) { return _dato ;}<br />

DatoNodo &operator = ( const DatoNodo &val) {<br />

Nodo :: operator = (val);<br />

_dato = val._dato;<br />

return *this;<br />

}


Continuamos :<br />

};<br />

const int operator == ( const DatoNodo &val) const {<br />

return (<br />

Nodo :: operator == (val) &&<br />

_data == val._dato ) ;<br />

}<br />

const int operator != ( const DatoNodo &val) const {<br />

return !( *this == val);<br />

}


9. COMPILAMOS UN PROGRAMA<br />

Un proyecto gran<strong>de</strong> <strong>de</strong>be ser repartido <strong>en</strong> secciones manejables, llamadas<br />

frecu<strong>en</strong>tem<strong>en</strong>te módulos. Dichos módulos se implem<strong>en</strong>tan <strong>en</strong> archivos separados.<br />

A gran<strong>de</strong>s rasgos, los módulos consist<strong>en</strong> <strong>en</strong> dos tipos <strong>de</strong> archivos :<br />

• Descripciones <strong>de</strong> interface, y<br />

• archivos <strong>de</strong> implem<strong>en</strong>tación.<br />

Para distinguir estos tipos, se usa un conjunto <strong>de</strong> sufijos cuando se compilan<br />

programas <strong>de</strong> C y <strong>C++</strong> :<br />

Ext<strong>en</strong>sión<br />

.h, .hxx, .hpp<br />

Tipo <strong>de</strong> archivo<br />

Descripciones <strong>de</strong> interface.<br />

(''cabecera'' o ''archivos incluidos'')<br />

.c Implem<strong>en</strong>tación <strong>de</strong> archivos <strong>de</strong> C.<br />

.cc, .C, .cxx,<br />

.cpp, .c++<br />

.tpl<br />

Implem<strong>en</strong>tación <strong>de</strong> archivos <strong>de</strong><br />

<strong>C++</strong>.<br />

Descripción <strong>de</strong> interface.<br />

( templates) (<strong>de</strong>finición <strong>de</strong><br />

plantillas).<br />

9.1. PASOS DE LA COMPILACION<br />

El proceso <strong>de</strong> compilación toma los archivos .cc, los preprocesa y los traduce <strong>en</strong><br />

archivos objeto.<br />

A continuación, el conjunto <strong>de</strong> archivos objeto es procesado por un linker. Este<br />

programa combina los archivos, aña<strong>de</strong> las bibliotecas necesarias y crea un ejecutable.<br />

.cc<br />

Compilador<br />

.h, .tpl<br />

.o<br />

Linker<br />

librerías<br />

a.out


En los or<strong>de</strong>nadores Alpha OSF/1 <strong>de</strong> la U.C.M., para compilar y linkar ( <strong>en</strong>lazar ) un<br />

programa basta con hacer:<br />

cxx nombre_<strong>de</strong>l_programa.cxx<br />

A continuación se explican las opciones <strong>de</strong> compilación más comunes.<br />

Para obt<strong>en</strong>er más información, teclear el comando:<br />

man cxx


10. FLUJO DE ENTRADA/SALIDA DE <strong>C++</strong><br />

Los usuarios pue<strong>de</strong>n especificar <strong>en</strong>tradas/salidas <strong>de</strong> tipos <strong>de</strong>finidos por usuario, así<br />

como <strong>de</strong> tipos estándar.<br />

10.1. ARCHIVOS DE CABECERA DE BIBLIOTECA IOSTREAM<br />

La mayor parte <strong>de</strong> los programas <strong>de</strong> <strong>C++</strong> <strong>de</strong>b<strong>en</strong> incluir el archivo <strong>de</strong> cabecera<br />

iostream.h, que conti<strong>en</strong>e información básica requerida para todas las operaciones <strong>de</strong><br />

flujo <strong>de</strong> <strong>en</strong>trada/salida. Este archivo conti<strong>en</strong>e los objetos cin, cout, cerr y clog, los<br />

cuales correspon<strong>de</strong>n al flujo <strong>de</strong> <strong>en</strong>trada estándar, flujo <strong>de</strong> salida estándar, flujo <strong>de</strong> error<br />

estándar y versión con memoria intermedia <strong>de</strong> cerr, respectivam<strong>en</strong>te.<br />

A<strong>de</strong>más <strong>de</strong>l operador


10.3. ENTRADAS/SALIDAS SIN FORMATO UTILIZANDO READ, GCOUNT Y<br />

WRITE<br />

Se lleva a cabo <strong>en</strong>tradas/salidas sin formato mediante las funciones miembro read y<br />

write. Cada una <strong>de</strong> estas funciones introduce o extrae, respectivam<strong>en</strong>te, un número<br />

<strong>de</strong>signado <strong>de</strong> caracteres <strong>de</strong> o <strong>de</strong>s<strong>de</strong> un arreglo <strong>de</strong> caracteres exist<strong>en</strong>te <strong>en</strong> memoria.<br />

La función gcount <strong>de</strong>termina el número <strong>de</strong> caracteres introducido.<br />

10.4. MANIPULADORES DE FLUJO<br />

<strong>C++</strong> proporciona varios manipuladores <strong>de</strong> flujo que cambian el formato por <strong>de</strong>fecto y<br />

el estado <strong>de</strong> la anchura Para utilizar manipuladores con parámetros, se <strong>de</strong>be incluir el<br />

archivo ''iomanip.h'':<br />

MANIPULADOR<br />

hex<br />

oct<br />

DESCRIPCION<br />

Cambia la base con la cual se interpretan los <strong>en</strong>teros<br />

<strong>de</strong>ntro <strong>de</strong> un flujo a hexa<strong>de</strong>cimal.<br />

Define a base octal.<br />

<strong>de</strong>c<br />

setbase<br />

setprecision<br />

width<br />

setw<br />

Devuelve la base <strong>de</strong>l flujo a <strong>de</strong>cimal.<br />

Toma un argum<strong>en</strong>to <strong>en</strong>tero 10, 8 o 16 para <strong>de</strong>finir la<br />

base. Necesita el archivo <strong>de</strong> cabecera iomanip.h.<br />

(Sin argum<strong>en</strong>to). Devuelve el ajuste actual <strong>de</strong> precisión<br />

<strong>de</strong> los números <strong>en</strong> punto flotante. (Lo mismo la función<br />

miembro precision).<br />

Define el ancho <strong>de</strong> campo y <strong>de</strong>vuelve el ancho anterior.<br />

Sin argum<strong>en</strong>to, <strong>de</strong>vuelve el ajuste pres<strong>en</strong>te.<br />

Define el ancho <strong>de</strong> campo.<br />

Los usuarios pue<strong>de</strong>n crear sus propios manipuladores <strong>de</strong> flujo.


11. EJERCICIOS<br />

1. Escriba un programa <strong>en</strong> <strong>C++</strong> que convierta la longitud <strong>de</strong>finida por el usuario <strong>en</strong> metros y<br />

c<strong>en</strong>tímetros.<br />

# inclu<strong>de</strong> <br />

# inclu<strong>de</strong> <br />

void main ( void )<br />

{<br />

float fMedidaUsuario,<br />

fConvMetros,<br />

fConvC<strong>en</strong>tim;<br />

}<br />

cout > fMedidaUsuario;<br />

while ( fMedidaUsuario > 0 ) {<br />

fConvMetros = fMedidaUsuario * 12 * 2.54;<br />

fConvC<strong>en</strong>tim = fConvMetros/100;<br />

cout


double calc_cosec ( void ) ;<br />

double calc_cotang ( void ) ;<br />

} grad<br />

void grado::pone_valor ( double ang )<br />

{<br />

pone_valor = ang ;<br />

}<br />

double grado::calc_s<strong>en</strong>( void )<br />

{<br />

double respuesta ;<br />

}<br />

respuesta = sin( grad_a_rad * valor_dato ) ;<br />

return( respuesta ) ;<br />

double grado::calc_cos( void )<br />

{<br />

double respuesta ;<br />

}<br />

respuesta = cos( grad_a_rad * valor_dato ) ;<br />

return( respuesta ) ;<br />

double grado::calc_tang( void )<br />

{<br />

double respuesta ;<br />

}<br />

respuesta = tan( grad_a_rad * valor_dato ) ;<br />

return( respuesta ) ;<br />

double grado::calc_sec( void )<br />

{<br />

double respuesta ;<br />

respuesta = 1.0 / sin( grad_a_rad * valor_dato ) ;<br />

return( respuesta ) ;<br />

}<br />

double grado::calc_cosec( void )<br />

{<br />

double respuesta ;<br />

}<br />

respuesta = 1.0 / cos( grad_a_rad * valor_dato ) ;<br />

return( respuesta ) ;<br />

double grado::calc_cotang( void )<br />

{<br />

double respuesta ;<br />

}<br />

respuesta = 1.0 / tan( grad_a_rad * valor_dato ) ;<br />

return( respuesta ) ;<br />

void main( void )<br />

{<br />

// Pone ángulo a 25.0 grados


grad.pone_valor( 25.0 ) ;<br />

cout


cout


}<br />

numero = pts ;<br />

cout


int absoluto::ab( int val1 )<br />

{<br />

int temp ;<br />

temp = abs( val1 ) ;<br />

return( temp ) ;<br />

}<br />

double absoluto::ab( double val2 )<br />

{<br />

double temp ;<br />

temp = abs( val2 ) ;<br />

return( temp ) ;<br />

}<br />

main( )<br />

{<br />

absoluto numero ;<br />

cout


ang.minutos = ( ( segundos + suma_angulo.segundos ) / 60 +<br />

minutos + suma_angulo.minutos ) % 60;<br />

ang.grados = ( ( segundos + suma_angulo.segundos ) / 60 +<br />

minutos + suma_angulo.minutos ) / 60;<br />

}<br />

ang.grados += grados + suma_angulo.grados;<br />

return ang;<br />

char *valor_angulo::salida_info( void )<br />

{<br />

char *ang[15];<br />

}<br />

// se requiere strstrea.h para el formato<br />

ostrstream( *ang, sizeof(ang) )


{<br />

cout


void escribe_kms_rodados( );<br />

};<br />

void r<strong>en</strong>ta_<strong>de</strong>_autos::cli<strong>en</strong>te_r<strong>en</strong>ta_<strong>de</strong>_autos( )<br />

{<br />

<strong>en</strong>trada_datos( );<br />

cout kms_auto_acum;<br />

cin.get( cr );<br />

}<br />

void r<strong>en</strong>ta_<strong>de</strong>_autos::escribe_kms_rodados( )<br />

{<br />

salida_datos( );<br />

cout


void main( void )<br />

{<br />

Estudiante_Est GrupoGran<strong>de</strong>[100];<br />

GrupoGran<strong>de</strong>[0].cursos = 10;<br />

LlamadaPorValor( GrupoGran<strong>de</strong>[0] );<br />

cout


12. BIBLIOGRAFIA<br />

Cómo programar <strong>en</strong> C/<strong>C++</strong>. H.M. Deitel / P.J. Deitel. Pr<strong>en</strong>tice Hall, 2ª ed. 1995.<br />

<strong>Programación</strong> ori<strong>en</strong>tada a objetos con <strong>C++</strong>. Fco. Javier Ceballos. Ed. ra-ma 1993.<br />

<strong>Programación</strong> <strong>en</strong> <strong>C++</strong>. Enrique Hernán<strong>de</strong>z / José Hernán<strong>de</strong>z. Ed. Paraninfo 1993.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!