Informática


Lenguaje C++


TEORIA DEL LENGUAJE C++

LECCION 1

INTRODUCCION AL CURSO DE C++ "

El objetivo de este curso es ense¤ar el lenguaje C++, o dicho de

otro modo, ense¤ar a programar en lenguaje C++.

INDICE DE ESTA LECCION "

En esta lecci¢n se va a estudiar los siguientes puntos:"

- Idea general y origen del lenguaje C++."

- Programaci¢n orientada a objetos (OOP)."

- Caracter¡sticas principales de la OOP:"

ú Encapsulaci¢n."

ú Herencia."

ú Polimorfismo"

- Forma de implementar las clases en C++."

IDEA GENERAL DEL LENGUAJE C++ "

Aunque C es uno de los mejores lenguajes de programaci¢n de prop¢-"

sito general, a medida que un sistema software se va haciendo m s"

grande se va acentuando m s algunas deficiencias del C, como es la"

asi ilimitada libertad que tiene el programador sobre las rutinas"

que se implementan. El C++ soluciona este problema facilitando la"

creaci¢n de unidades funcionales de caja negra que tienen acceso"

estrictamente controlado; a estas unidades se les llama objetos, por"

este motivo se dice que el ~C++ es un lenguaje orientado a objetos~."

ORIGEN "

El C++ se llam¢ originalmente ~C con clases~ y fue desarrollado por Bjarne"

Stroustrup de los laboratorios Bell en Murray Hill, New Jersey, en 1983."

El C++ se puede considerar como una ~ampliaci¢n del C est ndar~, por lo que"

la mayor parte de lo que conocemos del C es aplicable al C++."

Es necesario dejar claro en este momento que este tutor ense¤a el"

lenguaje C++, no la programaci¢n orientada a objetos (OOP), aunque"

la mayor¡a de los programas de C++ implementados en este tutor son"

programas orientados a objetos. Como el lenguaje C se estudi¢ en"

el tutor de C, ~en este tutor estudiaremos todas las caracter¡sticas

espec¡ficas del C++~, es decir, aquellas caracter¡sticas que posee"

el C++ y no las posee el C. Profundizaremos bastante en todas ellas"

de manera que no dejemos nada sin comentar. Como ya se dijo en el"

tutor de C, leyendo simplemente este tutor y libros de C++ no se"

aprende este lenguaje, sino que ~es imprescindible e ineludible pro-

gramar en C++~, y cuanto m s se programe, mejor se captar n los con-"

ceptos y m s r pido se aprender ."

PROGRAMACION ORIENTADA A OBJETOS "

Aunque acabamos de decir que el objetivo de este tutor es ense¤ar el"

lenguaje C++ y no la programaci¢n orientada a objetos, lo cual podr¡a"

ocupar otro tutor completo ya que es otra forma de programar y de pen-"

sar en t‚rminos program ticos, s¡ es pertinente mostrar cu les son las"

principales caracter¡sticas de esta nueva metodolog¡a de la programa-"

ci¢n. Estos rasgos principales los podemos resumir en tres: ~encapsula-

ci¢n, herencia y polimorfismo.

ENCAPSULACION

La programaci¢n orientada a objetos (OOP) est basada en la manipulaci¢n

de objetos. Un objeto es un concepto que alberga datos y funciones que

operan con esos datos~. Una vez que se ha implementado un objeto, lo £nico"

"que necesita saber un programador es la interface con la cual comunicarse"

"con ‚l."

Para entender mejor la idea de objeto, supongamos que un reloj digital es"

un objeto. Los datos ser¡an: la hora, la fecha, etc. La interface estar¡a"

formada por las funciones que manipulan esos datos: mostrar la hora, mos-"

rar la fecha, cambiar la hora, cambiar la fecha, etc. Observad que el"

usuario no necesita saber c¢mo est n implementadas tales funciones para"

manipular los datos; incluso se podr¡a cambiar la implementaci¢n de estas"

funciones y la interface seguir¡a siendo la misma."

Un ejemplo de objeto en programaci¢n podr¡a ser una pila. La interface"

estar¡a formada por dos funciones: apilar y desapilar. Al usuario del"

objeto no le importa cu les son los datos del objeto ni c¢mo est n im-"

lementadas estas dos funciones. El programador del objeto podr¡a dise-"

¤ar la pila como un array est tico y cambiar posteriormente la imple-"

mentaci¢n para que la pila est‚ dise¤ada como una lista din mica enla-"

zada. Al usuario de la pila no le afectar¡a en nada el cambio de dise¤o"

"en la pila, puesto que la interface seguir¡a siendo la misma, esto es,"

"formada por las funciones: apilar y desapilar."

" ~Los objetos tambi‚n reciben el nombre de tipo~ "

" ~abstracto de datos (TAD, DAT en ingl‚s).

" ~Y la encapsulaci¢n recibe tambi‚n el nombre

" ~de abstracci¢n de datos.

HERENCIA "

Una de las caracter¡sticas fundamentales en los lenguajes orientados"

a objetos es la herencia. Gracias a esto ~un determinado objeto puede

heredar" propiedades de otros objetos~. Estos v¡nculos nos permiten,"

n primer lugar, evitar informaciones duplicadas. Pero su importancia"

va mucho m s all , ya que el concepto de herencia implica una clasi-"

ficaci¢n y una interdependencia entre los objetos. Veamoslo con un"

ejemplo."

Supongamos que definimos el objeto animal. Este objeto abstracto tiene"

una serie de caracter¡sticas: es un ser vivo, necesita alimentarse, se"

reproduce, etc."

Acto seguido definimos el objeto mam¡fero indic ndole que es un animal."

Este objeto posee todas las caracter¡sticas de los animales y adem s le"

a¤ade nuevas caracter¡sticas: es vertebrado, tiene mamas, etc."

A continuaci¢n definimos el objeto persona indic ndole que es un mam¡-"

fero por lo que hereder todas las caracter¡sticas de los mam¡feros y"

de los animales. Adem s les a¤adimos otras que son propias a las perso-"

nas: habla, es racional, etc."

Por £ltimo, definimos el objeto alumno indic ndole que es una persona."

El objeto alumno tendr todas las caracter¡sticas de persona y tendr "

tambi‚n las suyas propias: matr¡cula, asignaturas que tiene, etc."

"Finalmente, definimos Antonio como una instanciaci¢n del objeto alumno,"

es decir, concretamos el objeto abstracto alumno sobre un elemento real,"

Antonio; no necesitamos definir nada. El lenguaje ya "sabe" que Antonio"

es un ser vivo, es vertebrado, etc."

POLIMORFISMO "

Vamos a explicar este concepto a trav‚s de dos ejemplos."

Imaginemos que tenemos dos pilas, una almacena n£meros enteros y la otra"

lmacena n£meros en coma flotante. Las dos funciones b sicas que podemos"

realizar con una pila son meter y sacar. Como tenemos dos pilas, podr¡a-"

mos implementar cuatro funciones diferentes con cuatro nombres diferentes:"

pilaint, desapilaint, apilafloat y desapilafloat. Aunque esto funcione,"

estamos complicando el programa a nivel conceptual. Utilizando la idea de"

polimorfismo podemos simplificar conceptualmente el programa implementando"

cuatro funciones con dos nombres diferentes: apila y desapila. Cuando in-"

voquemos, por ejemplo, a la funci¢n apila, el compilador deber determinar"

si llamamos a la funci¢n apila de la pila de n£meros enteros o a la funci¢n"

apila de la pila de n£meros en coma flotante. Las funciones apila y desapila"

se dice que est n sobrecargadas."

Los operadores tambi‚n se pueden sobrecargar en C++. De hecho ya est n so-"

brecargados en casi todos los lenguajes de programaci¢n. Por ejemplo, el"

operador + lo utilizamos en C y C++ para sumar operandos que pueden ser del"

tipo car cter, entero, coma flotante, etc."

"Veamos otro ejemplo interasente de polimorfismo que hace uso de la herencia."

Supongamos que tenemos definido el objeto punto con la funci¢n dibujar, la"

cual pinta un punto. A continuaci¢n definimos el objeto l¡nea que hereda las"

caracter¡sticas del objeto punto. En el objeto l¡na, utilizando la idea de"

polimorfismo, volvemos a definir la funci¢n dibujar, pero en este caso esta"

funci¢n traza una l¡nea; la funci¢n dibujar del objeto l¡nea puede utilizar,"

si lo desea, la funci¢n dibujar, heredada del objeto punto, para dibujar ca-"

da uno de los puntos de los que est constituida la l¡nea."

FORMA DE IMPLEMENTAR LAS CLASES "

Para terminar con esta introducci¢n al lenguaje C++ vamos a hacer una"

recomendaci¢n. Todos los programas ejemplos de esta lecci¢n est n en"

un s¢lo fichero. La mayor¡a de los ejemplos est n constituidos por la"

definici¢n de un tipo abstracto de datos (llamados clase en C++ as¡"

como a la instanciaci¢n de una clase se le llama objeto) y la funci¢n"

main para probar la clase definida. Los programas ejemplos se han rea-"

lizado en un s¢lo fichero para facilitar su exposici¢n y explicaci¢n"

en el tutor. No obstante, en la pr ctica es recomendable dividir el"

dise¤o de una clase en dos ficheros: un fichero ser¡a de cabecera (con"

extensi¢n .H) y en ‚l estar¡an todas las declaraciones de la clase, y"

el otro fichero ser¡a de c¢digo ejecutable (con extensi¢n .CPP) y en"

‚l estar¡an todas las definiciones relativas a la clase declarada. Al"

principio del fichero que tiene las definiciones hacemos un #include"

del fichero que contiene las declaraciones."

Cuando queramos utilizar esa clase en un programa de C++ tenemos dos"

posibilidades:"

1) Si el programa no lo hacemos como proyecto, simplemente hacemos"

un #include del fichero que contiene las definiciones de la clase al"

principio del fichero del programa."

2) Si el programa lo hacemos como proyecto, a¤adimos a la lista de"

ficheros del proyecto, el fichero de las definiciones de la clase,"

bien con extensi¢n .CPP o bien con extensi¢n .OBJ. Adem s hay que"

tener en cuenta que debemos hacer un #include del fichero con las"

declaraciones de la clase, en cada fichero del proyecto que utilice"

dicha clase."

LECCION 2

C++ COMO UNA MEJORA DEL C "

Esta lecci¢n explica las nuevas caracter¡sticas de C++ no

orientadas a objetos. Se trata de un importante n£mero de

peque¤as adiciones que hace el C++ sobre el C.

INDICE DE ESTA LECCION "

En esta lecci¢n se va a estudiar los siguientes puntos:"

- Nuevo estilo de comentario (con ~\\~)."

- Declaraciones (en cualquier sitio)."

- Los nombres de struct y enum son tipos."

- Operador de resoluci¢n de mbito (~::~)."

- Declaraciones por referencia (con el operador ~&~)."

- Uniones an¢nimas (uniones sin nombre)."

- Conversi¢n de tipo expl¡cita (notaci¢n funcional de los moldes)."

- Funciones en l¡nea (~inline~)."

- Argumentos por defecto."

- Funciones sobrecargadas (antiguamente se especificaba con ~overload~). "

- Operadores de almacenamiento libre (~new~ y ~delete~)."

- Entrada/Salida est ndar (con los flujos ~cout~ y ~cin~, y con los"

operadores sobrecargados ~<<~ y ~>>~, que se encuentran declarados"

en los ficheros de cabecera ~stream.h~ y ~iostream.h~)."

COMENTARIOS "

C++ introduce un nuevo estilo de comentario con el s¡mbolo ~//~. "

Este s¡mbolo indica comentario hasta final de l¡nea."

Ejemplos:"

int x; // a es una variable de tipo int"

int y; /* y es una variable de tipo int */"

DECLARACIONES "

En C, las declaraciones locales han de ir inmediatamente despu‚s de las"

llaves de comienzo de bloque. En C++ se puede declarar una variable en"

cualquier sitio, existiendo desde el punto de declaraci¢n hasta el final"

del bloque en la que se ha declarado."

Ejemplo:"

{

int x;"

x = 10;"

int y; // esta l¡nea no es correcta en C, pero s¡ en C++"

y = 20;"

}"

Una declaraci¢n muy frecuente en C++ es la siguiente:"

for (int i = iinic; i <= ifin; i++)"

{"

sentencias"

}

La variable i s¢lo tiene existencia en el bloque en

el que est declarada."

Ejemplo:

for (register int i = 0; i < IMAX; i++)

{

int t = v[i-1];

v[i-1] = v[i];"

" v[i] = t;

}

En C++, los nombres de enum y de struct son tipos. Esto nos permite"

hacer los siguiente:"

enum ecolores { rojo, verde, azul };

struct scolores { ecolores color; char nombre_color[20]; };

scolores color; // color es de tipo scolores

En C, las anteriores sentencias habr¡a que hacerlas del siguiente modo:

enum ecolores { rojo, verde, azul };

struct scolores { enum ecolores color; char nombre_color[20]; };

" struct scolores color; // color es de tipo struct scolores"

OPERADOR DE RESOLUCION DE AMBITO (::)

C es un lenguaje estructurado en bloque. C++ hereda los

mismos conceptos de bloque y mbito.

El operador ~::~ se usa del siguiente modo:"

~::variable

y tiene el significado de permitir el acceso a variable, "

que debe estar declarada externamente."

" // Ejemplo del operador ::"

" // Este programa imprime (r)3 1 2 1¯"

" #include <stdio.h>"

" int i = 1; // i externa"

" void main (void)"

{

" int i = 2; // i local a funci¢n main()"

" {"

" int i = 3; // i local al bloque en la que est declarada "

" printf ("%d %d ", i, ::i); // imprime (r)3 1¯"

}

" printf ("%d %d ", i, ::i); // imprime (r)2 1¯"

" }"

DECLARACIONES POR REFERENCIA Y LLAMADAS POR REFERENCIA "

"El operador ~&~ tiene en C++ un significado adicional a los que ya"

"tiene en C: declarar una variable o un par metro de una funci¢n"

"como referencia de otra variable."

"La forma general de declara una variable como referencia de otra es:"

" ~tipo & identificador = objeto

"Ejemplo:"

" #include <stdio.h>"

" void main (void)"

{

int i;"

int& i1 = i;"

int& i2 = i1;"

int& i3 = i2;"

i = 1;"

printf ("%d ", i1); // imprime (r)1¯"

i2 = 2;"

printf ("%d ", i3); // imprime (r)2¯"

" }"

"Otros ejemplos:"

double a[10];"

double& ultimo = a[9]; // ultimo es un alias para a[9]"

" char& nueva_linea = '\n';"

"El nombre ultimo es una alternativa para el elemento del array a[9]."

"Estos nombres, una vez que son inicializados, no pueden ser cambiados."

Tambi‚n es posible inicializar una referencia a un literal, lo cual"

crea una referencia a una localizaci¢n desconocida donde se almacena"

"el literal."

El uso principal del operador & con el significado que acabamos de describir"

se da en los argumentos pasados por referencia. Observar estas dos versiones"

"de la misma funci¢n:"

// estilo C // estilo C++"

void intercambiar (int *px, int *py) void intercambiar (int&x, int&y)"

{ {"

int aux = *px; int aux = x;"

*px = *py; x = y;"

*py = aux; y = x;"

} }"

Es obvio que la segunda versi¢n de la funci¢n intercambiar() es mucho m s"

clara que la primera."

Tambi‚n los valores devueltos por las funciones pueden ser por refe-"

rencia. Como es de suponer, el valor devuelto ha de ser una referencia"

a una variable no local a la funci¢n que devuelve el valor. Ejemplo:"

#include <stdio.h>"

int& f (int &x)"

{

return x;"

}"

void main (void)"

{

int y;"

f(y) = 20; // en realidad el 20 se asigna a y"

printf ("%d", y); // imprime (r)20¯"

}"

Estas dos funciones son incorrectas:"

int& f1 (void)"

{

int x = 10;"

return x;"

}"

int& f2 (void)"

{

return 10;"

}"

El compilador debe informar de error"

de compilaci¢n en ambos return."

UNIONES ANONIMAS "

Las uniones an¢nimas son las uniones que no "

tienen nombre. El C no dispone de ellas."

Ejemplo:"

// C++ // C"

union union"

{ {"

int d; int d;"

float f; float f;"

}; } u;"

f = 1.1; u.f = 1.1;"

printf ("%d", d); printf ("%d", u.d);"

CONVERSION DE TIPO EXPLICITA "

En C++, el nombre de un tipo puede ser usado como una funci¢n para realizar"

una conversi¢n de tipo. Esto supone una alternativa a los moldes."

Ejemplo:"

#include <stdio.h>"

void main (void)"

{"

int i = 10;"

float f1 = i; // conversi¢n de tipo impl¡cita"

float f2 = (float) i; // conversi¢n de tipo expl¡cita: notaci¢n molde"

float f3 = float (i); // conversi¢n de tipo expl¡cita: notaci¢n funcional"

printf ("%g %g %g", f1, f2, f3); // imprime (r)10 10 10¯"

}"

Otro ejemplo de conversi¢n expl¡-"

cita mediante notaci¢n funcional:"

struct st { int d; float f; };"

typedef st *pst;"

char *str = "abcdef";"

pst p = pst (str);"

FUNCIONES INLINE "

En el curso de C vimos que las macros pueden dar problemas como ‚ste:"

Dado"

#define CUAD(x) x*x"

la sentencia"

CUAD(a+b)"

expande a:"

a+b*a+b"

que no es evidentemente la expresi¢n esperada."

El problema puede ser evitado parentizando la definici¢n de la macro."

Sin embargo, la soluci¢n no protege contra tipos impropios."

El C++ ofrece una alternativa elegante"

y eficiente usando funciones inline:"

inline int cuad (int x)"

{

return x*x;"

}"

La palabra clave ~inline~ le dice al com-"

pilador que la funci¢n sea compilada"

como una macro, es decir, el especi-"

ficador inline fuerza al compilador de"

C++ a sustituir el cuerpo de c¢digo de"

cuad() en el lugar en que esta funci¢n"

es invocada."

Aunque el uso de inline incrementa la velocidad"

de ejecuci¢n porque se elimina la llamada a la"

funci¢n, produce un incremento del tama¤o del"

c¢digo, especialmente si la funci¢n inline con-"

tiene muchas l¡neas de c¢digo y es incovada mu-"

chas veces en el programa."

Otro ejemplo de funci¢n inline:"

inline void imprimir (int a, int b)"

{

printf ("\n%d", a);"

printf ("\n%d", b);"

}"

ARGUMENTOS POR DEFECTO "

Uno o m s argumentos en una funci¢n de C++ pueden ser especificado"

teniendo valores por defecto."

Ejemplo:"

#include <stdio.h>"

int mult (int x, int y = 1)"

{

return (x * y);"

}"

void main (void)"

{

printf ("%d %d", mult (5, 6), mult (7)); // imprime (r)30 7¯"

}"

S¢lo los par metros finales de una funci¢n pueden tener"

valores por defecto."

Ejemplo:"

void f1 (int i, int j = 2); // legal"

void f2 (int i = 3, int j); // ilegal"

void f3 (int i, int j = 4, int k = 5); // legal"

void f4 (int i = 6, int j = 7, int k = 8); // legal"

void f5 (int i, int j = 9, int k); // ilegal"

FUNCIONES SOBRECARGADAS "

El t‚rmino sobrecarga se refiere al uso del mismo nombre para varios"

significados de un operador o una funci¢n. El significado seleccionado "

depende de los tipos de los argumentos usados por el operador o la"

funci¢n."

El primer est ndar C++ introduc¡a la palabra clave ~overload~ para in-"

dicar que un nombre particular ser sobrecargado. En el nuevo est ndar"

de C++ se considera obsoleto el uso de esta instrucci¢n."

En este momento restringiremos nuestra discusi¢n a la sobrecarga de"

funciones y dejaremos la sobrecarga de operadores para lecciones pos-"

teriores."

// Ejemplo de sobrecarga de funciones"

overload media_array; // opcional en el nuevo est ndar de C++"

double media_array (double a[], int tam);"

double media_array (int a[], int tam);"

double media_array (int a[], int tam)"

{

int sum = 0;"

for (int i = 0; i < tam; ++i)"

sum += a[i]; // ejecuta aritm‚tica de enteros"

return ((double) sum / tam);"

}"

double media_array (double a[], int tam)"

{

double sum = 0.0;"

for (int i = 0; i < tam; ++i)"

sum += a[i]; // ejecuta aritm‚tica de double"

return (sum / tam);"

}"

El compilador elige autom ticamente la funci¢n"

que coincide con los tipos de los argumentos."

Atenci¢n: No se puede sobrecargar dos funciones"

que tengan iguales tipos de argumentos y dis-"

tintos tipos de valores devueltos. Es ilegal,"

por lo tanto, lo siguiente:"

overload f;"

int f (void);"

double f (void);"

OPERADORES DE ALMACENAMIENTO LIBRE (new y delete) "

Los operadores unarios ~new~ y ~delete~ est n disponibles para manipular "

el almacenamiento libre. Estos operadores reemplazan a las funciones"

de la biblioteca est ndar malloc(), calloc() y free(). En C++ se re-"

comienda usar estos operadores a tales funciones. El almacenamento"

libre se refiere al sistema por el cual el programador gestiona di-"

rectamente el tiempo de vida de los objetos. El programador crea el"

objeto usando new y lo destruye usando delete. Esto es importante"

para estructuras de datos din micas como las listas y los rboles."

El operador new se puede usar de las siguientes formas:"

new nombre_tipo"

new nombre_tipo inicializador"

new (nombre_tipo)"

En cada caso se producen dos efectos. Primero, es asignada la cantidad"

apropiada de almacenamiento para contener al nuevo tipo. Segundo, la"

direcci¢n base del objeto es devuelta como el valor de la expresi¢n"

new. La expresi¢n es de tipo void * y puede ser asignada a cualquier"

tipo puntero. Si no hay suficiente memoria, este operador devuelve nu-"

lo. El uso del operador con inicializador se aplica a las clases por"

lo que se explica en posteriores lecciones. Despu‚s del tipo puede ir"

entre corchetes el n£mero de elementos de ese tipo a reservar."

Ejemplos:"

int *pi; char *pc; float *pf; int n = 2;"

pi = new int; pc = new char[10]; pf = new float[n];"

*pi = 5; strcpy (pc, "hola"); pf[0] = 1.1; pf[1] = 2.2;"

El operador delete destruye un objeto creado por new dejando libre"

el espacio ocupado por este objeto para poder ser reusado. El opera-"

dor delete se puede usar de las siguientes formas:"

delete expresion"

delete [expresion] expresion"

La primera forma es la m s com£n. La expresi¢n es normalmente una"

variable puntero usada en una expresi¢n new previa. La segunda forma"

es utilizada menos frecuentemente y se usa cuando se asign¢ un array"

con new. La expresi¢n entre corchetes especifica el n£mero de ele-"

mentos del array a liberar. Dicho tama¤o del vector proporcionado"

por el usuario es ignorado excepto para algunos tipos definidos por"

el usuario (referencia: apartado "Vectores de objetos de clases" en"

lecci¢n 4 del tutor de C++). El operador delete no devuelve ning£n"

valor (o tambi‚n se puede decir que su tipo devuelto es void). El"

operador delete s¢lo puede ser aplicado a punteros devueltos por new"

o a cero; aplicar delete a cero no tiene ning£n efecto."

ENTRADA/SALIDA ESTANDAR EN C++ "

La E/S est ndar en C++ se va a estudiar en detalle en lecciones pos-"

teriores. Aqu¡ s¢lo se va a comentar los conocimientos m¡nimos para"

poder utilizarla en los ejemplos."

En el primer est ndar de C++, la utilizaci¢n de las facilidades de E/S"

necesitaba la inclusi¢n del fichero de cabecera ~<stream.h>~. En el nuevo"

est ndar es preferible utilizar el fichero de cabecera ~<iostream.h>~ que"

mejora y a¤ade nuevas caracter¡sticas a <stream.h>. Lo que se va a co-"

mentar en este momento requiere uno de los dos ficheros de cabecera an-"

teriores; si el compilador que usas no contiene el fichero iostream.h,"

seguro que tiene el stream.h."

A partir de este momento, la salida est ndar la realizaremos con el"

identificador ~cout~ y el operador sobrecargado ~<<~, y la entrada est ndar"

la realizaremos con el identificador ~cin~ y el operador sobrecargado ~>>~."

Para poder utilizar en un programa los identificadores cout, cin y sus"

correspondientes operadores sobrecargados, tenemos que hacer al princi-"

pio de esto:"

#include <iostream.h> // para los compiladores que no dispongan de"

// este fichero: #include <stream.h>"

// Ejemplo de c¢mo utilizar la E/S de C++"

#include <iostream.h>"

void main (void)"

{

// equivalente a printf ("C++ es un C mejorado.\n");"

cout << "C++ es un C mejorado.\n";"

// equivalente a printf ("2 + 2 = %d\n", 2 + 2);"

cout << "2 + 2 = " << 2 + 2 << '\n';"

int n;"

cin >> n; // equivalente a scanf ("%d", &n);"

float f1, f2;"

cin >> f1 >> f2; // equivalente a scanf ("%f%f", &f1, &f2); "

}"

Los identificadores cout y cin son los"

nombres de los flujos de salida y entrada"

est ndar, respectivamente. Los operadores"

<< y >> indican la direcci¢n del flujo de"

informaci¢n."

LECCION 3

CLASES "

~ Esta lecci¢n describe las facilidades de C++ para definir nuevos tipos ~ "

~ en los cuales el acceso a los datos est restringido a un conjunto es-

~ pec¡fico de funciones. A estos nuevos tipos se les denomina tipos abs-

~ tractos de datos (TAD en castellano y ADT en ingl‚s).

~ Una clase (class) es una extensi¢n de la idea de estructura (struct)

~ en C. El nombre original dado por Stroustrup a este lenguaje fue "C

~ con clases".

~ Una estructura en C est compuesta por un conjunto de datos. Una clase

~ o una estructura en C++ est compuesta de un conjunto de datos junto

~ con un conjunto de funciones y operadores para manipular esos datos.

INDICE DE ESTA LECCION "

En esta lecci¢n se va a estudiar los siguientes puntos:"

- El tipo compuesto ~struct~."

- Visibilidad de los miembros de un objeto (~private~ y ~public~)."

- Tipos compuestos ~struct~ y ~class~."

- Declaraci¢n de funciones miembros."

- Operador de resoluci¢n de mbito (~::~)."

- Miembro ~static~."

- Clases anidadas."

- Estructuras y uniones (~struct~ y ~union~)."

- Punteros a miembros (~::*~, ~.*~ y ~->*~)."

- Precedencia de operadores."

EL TIPO COMPUESTO struct "

En C++, a los elementos de una estructura "

se les llama ~miembros~. Adem s, extiende"

el concepto de estructura."

Para explicar estas mejoras vamos a hacer"

dos versiones de un mismo programa: la"

primera versi¢n utilizando el concepto de"

struct del C y la segunda utilizando el"

concepto de struct del C++."

DOS VERSIONES DE UN MISMO PROGRAMA "

// VERSION 1. UTILIZA CONCEPTO DE STRUCT DEL C

#include <iostream.h> // cout, << sobrecargado; tambi‚n vale <stream.h>"

const int longit_max = 1000;"

enum boolean { false, true };"

struct pila"

{

char s[longit_max]; // no permitido en el ANSI C, s¡ en el ANSI C++"

int cima;"

};

void inicializar (pila *pil)"

{

pil->cima = 0;"

}

void meter (char c, pila *pil)"

{

pil->s[++pil->cima] = c;"

}

char sacar (pila *pil)"

{

return (pil->s[pil->cima--]);"

}

char elem_cima (pila *pil)"

{

return (pil->s[pil->cima]);"

}

boolean vacia (pila *pil)"

{

return boolean (pil->cima == 0);"

}

boolean llena (pila *pil)"

{

return boolean (pil->cima == longit_max - 1);"

}

void main (void)"

{

pila p;"

char *cad;"

inicializar (&p);"

cad = "Ejemplo de struct del C.";"

for (register int i = 0; cad[i]; i++)"

if (! llena (&p))"

meter (cad[i], &p);"

cout << "Cadena original: " << cad << "\n";"

cout << "Cadena invertida: ";"

while (! vacia (&p))"

cout << sacar (&p);"

cout << "\n";"

}

// VERSION 2. UTILIZA CONCEPTO DE STRUCT DEL C++

#include <iostream.h> // cout, << sobrecargado; tambi‚n vale <stream.h>"

const int longit_max = 1000;"

enum boolean { false, true };"

struct pila"

{

private:"

char s[longit_max]; // const no permitida en inicializac. en ANSI C"

int cima;"

public:"

void inicializar (void)"

{"

cima = 0;"

}"

void meter (char c)"

{"

s[++cima] = c;"

}"

char sacar (void)"

{"

return (s[cima--]);"

}"

char elem_cima (void)"

{"

return (s[cima]);"

}"

boolean vacia (void)"

{"

return boolean (cima == 0);"

}"

boolean llena (void)"

{"

return boolean (cima == longit_max - 1);"

}"

};

void main (void)"

{

pila p;"

char *cad;"

p.inicializar ();"

cad = "Ejemplo de struct del C++.";"

for (register int i = 0; cad[i]; i++)"

if (! p.llena ())"

p.meter (cad[i]);"

cout << "Cadena original: " << cad << "\n";"

cout << "Cadena invertida: ";"

while (! p.vacia ())"

cout << p.sacar ();"

cout << "\n";"

}

SALIDA DE LOS PROGRAMAS:

La salida del primer programa es:"

Cadena original: Ejemplo de struct del C."

Cadena invertida: .C led tcurts ed olpmejE"

y la del segundo:"

Cadena original: Ejemplo de struct del C++."

Cadena invertida: .++C led tcurts ed olpmejE"

Los dos son iguales excepto en el mensaje que invierten."

ANALISIS DE LOS EJEMPLOS:

En nuestro primer programa no aparece ning£n concepto nuevo y el usuario"

debe entenderlo todo. En el segundo programa s¡ aparecen unos cuantos"

conceptos nuevos del C++."

La primera novedad que se aprecia es que hay definida funciones dentro"

de la estructura. En C, las estructuras s¢lo pueden tener datos miembros,"

en C++, las estructuras tambi‚n pueden contener ~funciones miembros~."

Algunos libros se refieren a las funciones miembros como m‚todos. Las"

variables de tipo estructura reciben el nombre de objetos."

Como se aprecia en la funci¢n main(), a las funciones de una variable"

estructura se accede igual que a los datos de esa estructura, es decir,"

con el operador punto (.)."

La segunda novedad que vemos en la estructura del ejemplo son las pala-"

bras claves ~private~ y ~public~, las cuales hacen que los miembros de"

la estructura sean privados o p£blicos, respectivamente. A los miembros"

privados s¢lo pueden acceder las funciones miembros. A los miembros"

p£blicos puede acceder cualquier funci¢n del programa."

La £ltima novedad que aparece en el programa es la definici¢n impl¡cita"

de funciones ~inline~: todas aquellas funciones que se definen (no que"

se declaran) dentro de una estructura son inline, aunque no vayan prece-"

didas por la palabra clave inline."

Estas tres novedades de las estructuras de C++ con respecto al C se van"

a discutir m s ampliamente en los apartados siguientes. Intenta entender"

el segundo programa antes de pasar a las siguientes ventanas e intenta"

apreciar la diferencia que existe con respecto a la primera versi¢n del"

mismo programa."

VISIBILIDAD DE LOS MIEMBROS DE UN OBJETO "

Desde el punto de vista de la visibilidad o el acceso a los miembros"

de un objeto, los miembros pueden ser ~p£blicos~, ~privados~ o ~protegidos~."

Los miembros protegidos se estudian en lecciones posteriores."

Los miembros privados son aqu‚llos que est n bajo el mbito de la"

palabra clave private seguida por dos puntos (~private:~). Del mismo"

modo, los miembros p£blicos son aqu‚llos que est n bajo el mbito"

de la palabra clave public seguida por dos puntos (~public:~)."

Los miembros privados s¢lo pueden ser accedidos por las funciones"

miembros."

Los miembros p£blicos constituyen la interface con los elementos"

de la clase."

Si todos los miembros de una clase, datos y funciones, son privados,"

no hay ninguna forma de que el programa se pueda comunicar con los"

elementos de ese objeto."

EJEMPLO SOBRE EL ACCESO A LOS MIEMBROS DE UNA CLASE "

void main (void)"

{

struct"

{"

private:"

int x;"

void f1 (void) { x = 10; }"

void f2 (void) { y = 10; }"

public:"

int y;"

void f3 (void) { x = 20; }"

void f4 (void) { y = 20; }"

void f5 (void) { f1 (); f2 (); f3 (); }"

} s;"

s.x = 1; // ilegal: error de compilaci¢n. Miembro x no accesible."

s.f1 (); // ilegal: error de compilaci¢n. Miembro f1() no accesible."

s.f2 (); // ilegal: error de compilaci¢n. Miembro f2() no accesible."

s.y = 2; // legal"

s.f3 (); // legal"

s.f4 (); // legal"

s.f5 (); // legal"

}

TIPOS COMPUESTOS struct Y class "

Los tipos struct y class son similares. S¢lo hay una diferencia entre ellos:"

los miembros de una estructura son por defecto p£blicos, y los miembros de

una clase son por defecto privados~. Esto supone que las palabras claves pri-"

vate y public son opcionales."

En este tutor, por convenci¢n, los objetos que s¢lo contengan"

datos se declarar n como struct, y aqu‚llos que contengan datos"

y funciones se declarar n como class."

EJEMPLOS DE TIPOS EQUIVALENTES "

~struct s ~ ~struct s

~ { ~ ~ {

~ int i; ~ <===> ~ public:

~ void f (void); ~ ~ int i;

~ }; ~ ~ void f (void);

~ ~ ~ };

~class c ~ ~class c

~ { ~ ~ {

~ int i; ~ <===> ~ private:

~ void f (void); ~ ~ int i;

~ }; ~ ~ void f (void);

~ ~ ~ };

~struct s ~ ~class c

~ { ~ ~ {

~ int i; ~ <===> ~ public:

~ void f (void); ~ ~ int i;

~ }; ~ ~ void f (void);

~ ~ ~ };

~class c ~ ~struct s

~ { ~ ~ {

~ public: ~ ~ int i;

~ int i; ~ <===> ~ void f (void);

~ void f (void);~ ~ };

~ }; ~ ~

~struct s ~ ~class c

~ { ~ ~ {

~ int i; ~ <===> ~ void f (void);

~ ~ ~

~ private: ~ ~ public:

~ void f (void);~ ~ int i;

~ } ~ ~ };

DECLARACION DE FUNCIONES MIEMBROS "

Antes de que se pueda utilizar una clase,"

todos sus miembros deben estar definidos."

DOS FORMAS DE DEFINIR UNA FUNCION MIEMBRO "

1) Definir la funci¢n miembro dentro de la clase. En este caso, aunque"

la definici¢n de la funci¢n no vaya precedida por la palabra inline, la"

funci¢n es inline y ser tratada como una macro. Naturalmente, se puede"

utilizar la palabra clave inline si se desea, aunque no sea necesario"

con las funciones miembros."

2) Declarar la funci¢n dentro de la clase, es decir, escribir su proto-"

tipo dentro de la clase, y definirla fuera, es decir, en el mbito ex-"

terno. En este caso, el nombre de la funci¢n miembro en la definici¢n"

debe ir precedido con el nombre de la clase seguido por el operador de"

resoluci¢n de mbito (::). El nombre de la clase es necesario porque"

puede haber otras clases que utilicen el mismo nombre de funci¢n."

Las funciones miembros, al igual, que las dem s funciones, tambi‚n se"

pueden sobrecargar y sus argumentos pueden tener valores por defecto."

EJEMPLO DE DECLARACION DE FUNCIONES MIEMBROS "

#include <iostream.h>"

class clase"

{

private:"

int x;"

public:"

inline void inicializar (void); // declaraci¢n de funci¢n inline"

void asignar (int y) { x = y; } // definici¢n de funci¢n inline"

int devolver (void); // declaraci¢n de funci¢n no inline"

};

void clase::inicializar (void)"

{

x = 0;"

}

int clase::devolver (void)"

{

return x;"

}

void main (void)"

{

clase c;"

cout << (c.inicializar (), c.devolver ())"

<< ' '"

<< (c.asignar (100), c.devolver ())"

<< '\n'; // imprime: (r)0 100¯"

}

OPERADOR DE RESOLUCION DE AMBITO (::) "

En la lecci¢n anterior dijimos que pod¡amos referirnos"

explic¡tamente a un miembro externo de la siguiente forma: "

~::identificador

Otra forma de utilizar este operador es:"

~clase::identificador

lo cual es £til para distinguir explic¡tamente entre los"

nombres de miembros de clase y otros nombres."

En las dos expresiones anteriores identificador puede ser"

tanto el nombre de una variable como el nombre de una"

funci¢n."

El operador unario ~::~ tiene la misma prioridad que los operadores "

monarios ~()~, ~[]~, ~->~ y ~.~, esto es, tiene la prioriodad m s alta."

EJEMPLO DEL OPERADOR DE RESOLUCION DE AMBITO "

#include <iostream.h>"

int x;"

class clase"

{

private:"

int x;"

public:"

void asigx (void) { x = 2; }"

int devexpr (void) { return (x + clase::x + ::x); }"

};

void main (void)"

{

clase c;"

x = 1;"

c.asigx ();"

cout << c.devexpr () << " " << x + ::x; // imprime (r)5 2¯"

}

MIEMBRO static "

Los datos miembros pueden ser declarados con el modificador"

de clase de almacenamiento static. No pueden ser declarados"

auto, register o extern. ~Un dato miembro que es declarado

~static es compartido por todas las variables de esa clase

~y es almacenado en un lugar £nicamente.~ A causa de esto, se"

accede a este miembro, desde fuera de la clase, en la forma"

nombre_de_clase::identificador si tiene visibilidad p£blica. "

EJEMPLO DE MIEMBRO static "

#include <iostream.h>"

struct estructura"

{

int x;"

static int y;"

};

int estructura::y = 0;"

void main (void)"

{

estructura c1, c2, c3;"

estructura::y++;"

c1.y++;"

c2.y++;"

c3.y++;"

c1.x = c2.x = c3.x = 0;"

c1.x++;"

c2.x++;"

c3.x++;"

cout << estructura::y << c1.y << c2.y << c3.y; // imprime (r)4444¯"

cout << c1.x << c2.x << c3.x; // imprime (r)111¯"

}

CLASES ANIDADADAS "

Las clases se pueden anidar. ~La clase interna no est dentro

del mbito de la clase externa, sino que est en el mismo

mbito que la clase externa.~ Puesto que esto puede conducir"

a confusi¢n, es preferible no utilizar clases anidadas."

EJEMPLO DE CLASES ANIDADAS "

char c; // mbito exterior"

class x // declaraci¢n de clase exterior"

{

char c;"

class y // declaraci¢n de clase interior"

{"

char d;"

void f (char e) { c = e; }"

};"

char g (x* q) { return q->d; } // error de sintaxis "

};

COMENTARIO SOBRE EL EJEMPLO ANTERIOR "

La funci¢n miembro f de class y, cuando usa c, est usando la c de mbito"

externo. Es como si class y estuviese declarada en el mismo nivel y el"

mismo bloque interior o mbito de fichero que class x. La funci¢n miembro"

g de class x, cuando usa d, est intentando acceder al miembro privado de"

class x, lo cual produce un error de compilaci¢n."

ESTRUCTURAS Y UNIONES "

Hemos dicho que una estructa es simplemente una"

clase con todos sus miembros p£blicos, esto es"

struct s { ..."

es una forma corta de escribir"

class s { public: ..."

Las estructuras se usan cuando no se quiere ocultar "

los datos."

Una uni¢n (union) se define como una estructura (struct)

donde todos sus miembros tienen la misma direcci¢n.

Los especificadores de acceso de C++ (public, private"

y protected) no pueden ser usados en las uniones."

EJEMPLO DE union "

#include <iostream.h>"

union un"

{

int x;"

float y;"

void asigx (int xx) { x = xx; }"

void asigy (float yy) { y = yy; }"

int devx (void) { return x; }"

float devy (void) { return y; }"

};

"void main (void)"

{

un u;"

u.x = 15;"

cout << u.devx () << '\n'; // imprime (r)15¯"

u.y = 5.5;"

cout << u.devy () << '\n'; // imprime (r)5.5¯"

u.x = 15;"

cout << u.devy () << '\n'; // imprime valor indefinido"

u.y = 5.5;"

cout << u.devx () << '\n'; // imprime valor indefinido"

}

PUNTEROS A MIEMBROS "

Es posible tomar la direcci¢n de un miembro de una clase.

Con los operadores de resoluci¢n de mbito (~::~) y de contenido (~*~)"

podemos declarar un puntero a un miembro de una clase."

Ejemplo:"

int cl::*pcl; // pcl es un puntero a un miembro entero de la clase cl"

Los operadores . y * forman un nuevo operador en C++, ~.*~, con el cual"

referenciamos un miembro de una clase a trav‚s de un puntero al miembro"

de esa clase."

En la siguiente ventana se muestra un ejemplo del uso de este operador."

EJEMPLO DEL OPERADOR .* "

#include <iostream.h>"

class cl"

{

public:"

int suma;"

void cl::sumatorio (int x);"

};

void cl::sumatorio (int x)"

{

suma = 0;"

for (register int i = x; i; i--)"

suma += i;"

}

void main (void)"

{

int cl::*pi; // puntero a un miembro de cl que es de tipo int"

void (cl::*pf) (int x); // puntero a una funci¢n miembro de cl que"

// devuelve void y acepta un int como par metro"

cl clase; // clase es un objeto de tipo cl"

pi = &cl::suma; // obtiene direcci¢n del dato miembro suma"

pf = &cl::sumatorio; // obtiene direcci¢n de la funci¢n miembro"

// sumatorio"

(clase.*pf) (5); // calcula el sumatorio de 5"

cout << "El sumatorio de 5 es " << clase.*pi << "\n";"

}

Los operadores -> y * forman un nuevo operador en C++, ~->*~, con el cual"

referenciamos un miembro de una clase referenciando un puntero a un"

miembro de esa clase a trav‚s de un puntero a la clase."

En la siguiente ventana se muestra un ejemplo del uso de este operador."

EJEMPLO DEL OPERADOR ->* "

#include <iostream.h>"

class cl"

{

public:"

int suma;"

void cl::sumatorio (int x);"

};

void cl::sumatorio (int x)"

{

suma = 0;"

for (register int i = x; i; i--)"

suma += i;"

}

void main (void)"

{

int cl::*pi; // puntero a un miembro de cl que es de tipo int"

void (cl::*pf) (int x); // puntero a una funci¢n miembro de cl que"

// devuelve void y acepta un int como par metro"

cl clase; // clase es un objeto de tipo cl"

cl *pcl; // pcl es un puntero a un objeto del tipo cl"

pcl = &clase; // asigna a pcl la direcci¢n del objeto clase"

pi = &cl::suma; // obtiene direcci¢n del dato miembro suma"

pf = &cl::sumatorio; // obtiene direcci¢n de la funci¢n miembro"

// sumatorio"

(pcl->*pf) (5); // calcula el sumatorio de 5 usando -> para llamar"

// a la funci¢n"

cout << "El sumatorio de 5 es " << pcl->*pi << "\n"; // usa -> para acceder"

// a un dato miembro"

}

PRECEDENCIA DE OPERADORES "

Una vez vistos todos los operadores que a¤ade el C++ al lenguaje C (new,"

(delete, ::, .*, ->*) vamos a mostrar la tabla de precedencia completa de"

los operadores de C++."

ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ"

Precedencia de Operadores"

ßßßßßßßßßßßßßßßßßßßßßßßßßßß"

En la siguiente tabla de precedencia de operadores, los operadores son"

divididos en 16 categor¡as."

La categor¡a #1 tiene la precedencia m s alta; la categor¡a #2 (operadores"

unarios) toma la segunda precedencia, y as¡ hasta el operador coma, el"

cual tiene la precedencia m s baja."

Los operadores que est n dentro de una misma categor¡a tienen igual"

precedencia."

Los operadores unarios (categor¡a #2), condicional (categor¡a #14), y"

de asignaci¢n (categor¡a #15) se asocian de derecha a izquierda; todos"

los dem s operadores se asocian de izquierda a derecha."

ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ"

# Categor¡a ³ Operador ³ Qu‚ es (o hace)"

ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ"

1. M s alto ³ () ³ Llamada a funci¢n"

³ [] ³ Indexamiento de array"

³ -> ³ Selector de componente indirecta de C++"

³ :: ³ Resoluci¢n/acceso de mbito de C++"

³ . ³ Selector de componente directa de C++"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

2. Unario ³ ! ³ Negaci¢n L¢gica (NO)"

³ ~ ³ Complemento a 1"

³ + ³ M s unario"

³ - ³ Menos unario"

³ ++ ³ Preincremento o postincremento"

³ -- ³ Predecremento o postdecremento"

³ & ³ Direcci¢n"

³ * ³ Contenido (indirecci¢n)"

³ sizeof ³ (devuelve tama¤o de operando, en bytes)"

³ new ³ (asignador de memoria din mica en C++)"

³ delete ³ (desasignador de memoria din mica en C++)"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

3. Multipli- ³ * ³ Multiplica"

cativo ³ / ³ Divide"

³ % ³ Resto (m¢dulo)"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

4. Acceso a ³ .* ³ Operador de referencia de una direcci¢n en C++."

los miembros ³ ->* ³ Operador de referencia de una direcci¢n en C++."

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

5. Aditivo ³ + ³ M s binario"

³ - ³ Menos binario"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

6. Desplaza- ³ << ³ Desplazamiento a la izquierda"

miento ³ >> ³ Desplazamiento a la derecha"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

7. Relacional ³ < ³ Menor que"

³ <= ³ Menor o igual que"

³ > ³ Mayor que"

³ >= ³ Mayor o igual que"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

8. Igualdad ³ == ³ Igual a"

³ != ³ Distinto a"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

9. ³ & ³ AND entre bits"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

10. ³ ^ ³ XOR entre bits"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

11. ³ | ³ OR entre bits"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

12. ³ && ³ AND l¢gico"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

13. ³ || ³ OR l¢gico"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

14. Condicional³ ?: ³(a ? x : y significa "si a entonces x, si no y")"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

15. Asignaci¢n ³ = ³ Asignaci¢n simple"

³ *= ³ Asignar producto"

³ /= ³ Asignar cociente"

³ %= ³ Asignar resto (m¢dulo)"

³ += ³ Asignar suma"

³ -= ³ Asignar diferncia"

³ &= ³ Asignar AND entre bits"

³ ^= ³ Asignar XOR entre bits"

³ |= ³ Asignar OR entre bits"

³ <<= ³ Asignar desplazamiento hacia la izquierda"

³ >>= ³ Asignar desplazamiento hacia la derecha"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"

16. Coma ³ , ³ Evaluar"

ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ"

Todos los operadores de la tabla se pueden sobrecargar (referencia de sobre-"

carga de operadores en lecci¢n 5 del tutor de C++) excepto los siguientes:"

. Selector de componente directa de C++"

.* Referencia en C++"

:: Resoluci¢n/acceso de mbito en C++"

?: Condicional"

; LECCION 4

CONSTRUCTORES Y DESTRUCTORES "

~ Esta lecci¢n gira en torno a los constructores ~ "

~ y destructores.

~ Un constructor es una funci¢n miembro de un

~ objeto que es llamada autom ticamente cuando

~ se crea el objeto. Tiene el mismo nombre de

~ la clase.

~ Un destructor es una funci¢n miembro de un

~ objeto que es llamada autom ticamente cuando

~ se destruye el objeto. Tiene el mismo nombre

~ de la clase precedido por ~~.

INDICE DE ESTA LECCION "

En esta lecci¢n se va a estudiar los siguientes puntos: "

- Concepto de constructor y destructor."

- Constructores y destructores de objetos est ticos."

- Almacenamiento libre."

- Vectores de objetos de clase."

- Objetos como miembros."

- Autorreferencia: el puntero this."

- Funciones miembros constantes."

- Funciones miembros vol tiles."

CONCEPTO DE CONSTRUCTOR Y DESTRUCTOR "

Un ~constructor~ es una funci¢n miembro que tiene el mismo nombre "

que la clase. Los constructores se utilizan normalmente para"

inicializar datos miembros y asignar memoria usando new. Un"

~destructor~ es una funci¢n miembro que tiene el mismo nombre que"

la clase precedido por el car cter ~~. Los destructores se uti-"

lizan normalmente para liberar, usando delete, la memoria asig-"

nada por el constructor."

Los constructores pueden sobrecargarse y pueden tomar argumentos;"

en los destructores no se permite ninguna de estas dos cosas. Los"

constructores y los destructores no devuelven nada."

Los constructores son invocados autom ticamente cuando se crea el"

objeto. Los destructores son invocados autom ticamente cuando se"

destruye el objeto."

EJEMPLO DE CONSTRUCTOR "

#include <iostream.h>"

class clase"

{

int x;"

public:"

clase (int i) { x = i; }"

int devx (void) { return x; }"

};

void main (void)"

{

clase c1; // error de compilaci¢n"

clase c2 (2);"

cout << c2.devx (); // imprime (r)2¯"

}

EJ. DE CONSTR. CON ARGS. POR DEFECTO "

;

#include <iostream.h>"

class clase"

{

int x;"

public:"

clase (int i = 0) { x = i; }"

int devx (void) { return x; }"

};

void main (void)"

{

clase c1, c2 (1);"

cout << c1.devx (); // imprime (r)0¯"

" cout << c2.devx (); // imprime (r)1¯"

}

EJEMPLO DE CONSTRUCTOR SOBRECARGADO "

#include <iostream.h>"

class clase"

{

int x;"

public:"

clase (void) { x = 0; }"

clase (int i) { x = i; }"

int devx (void) { return x; }"

};

void main (void)"

{

clase c1;"

clase c2 (5);"

clase c3 (); // atenci¢n: esto es el prototipo de una funci¢n"

cout << c1.devx (); // imprime (r)0¯"

cout << c2.devx (); // imprime (r)5¯"

cout << c3.devx (); // error de compilaci¢n: c3 no es objeto sino func."

}

EJEMPLO DE CONSTRUCTOR Y DESTRUCTOR "

#include <iostream.h> // para utilizar: cout, << sobrecargado"

enum boolean { false, true };"

class pila"

{

private: // representaci¢n oculta para el TAD pila"

char *s;"

int longit_max;"

int cima;"

public: // interface p£blica para el TAD pila"

pila (void) { s = new char[100]; longit_max = 100; cima = 0; }"

pila (int tam) { s = new char[tam]; longit_max = tam; cima = 0; }"

pila (int tam, char str[]);"

~pila (void) { delete s; }"

void inicializar (void) { cima = 0; }"

void meter (char c) { s[++cima] = c; }"

char sacar (void) { return (s[cima--]); }"

char elem_cima (void) { return (s[cima]); }"

boolean vacia (void) { return boolean (cima == 0); }"

boolean llena (void) { return boolean (cima == longit_max - 1); }"

};

pila::pila (int tam, char str[])"

{

s = new char[tam];"

longit_max = tam;"

for (register int i = 0; i < longit_max && str[i] != 0; i++)"

s[i+1] = str[i];"

cima = i;"

}

void main (void)"

{

char *cad = "Ejemplo";"

pila p (20, cad);"

cout << "Cadena original: " << cad << "\n"; // imprime (r)Ejemplo¯"

cout << "Cadena invertida: ";"

while (! p.vacia ()) // imprime (r)olpmejE¯"

cout << p.sacar ();"

cout << "\n";"

}

CONSTRUCTORES Y DESTRUCTORES DE OBJETOS ESTATICOS "

En algunas implementaciones est indefinido si el constructor"

para un objeto est tico local es llamado o no en la funci¢n que"

es declarado. Esto quiere decir que los argumentos de los cons-"

tructores para objetos est ticos deben ser expresiones contantes "

en tales implementaciones. Por ejemplo:"

void f (int a)"

{"

static clase c (a); // error en algunos sistemas"

}

EJEMPLO DE FUNCIONAMIENTO DE OBJETOS ESTATICOS LOCALES EN TURBO C++ "

#include <iostream.h>"

class clase"

{

public:"

int x;"

clase (int i) { x = i; }"

};

void f (int a)"

{

static clase c (a); // el constructor es invocado en primera llamada a f()"

cout << c.x;"

}

void main (void)"

{

f (10); // imprime (r)10¯"

f (20); // imprime (r)10¯"

}

Si un programa termina usando la funci¢n exit(), se llamar a los"

destructores para los objetos est ticos, pero si el programa ter-"

mina usando la funci¢n abort(), no se llamar a tales destructores."

Notad que esto implica que exit() no termina un programa inmediata- "

mente. LLamar a exit() en un destructor puede causar una recursi¢n"

infinita."

ALMACENAMIENTO LIBRE "

Consideremos el ejemplo:"

#include <iostream.h>"

class clase"

{"

char *s;"

public:"

clase (int n) { s = new char[n]; }"

~clase (void) { delete s; }"

};"

void main (void)"

{

clase *p = new clase (10);"

clase *q = new clase (20);"

delete p;"

delete p; // posiblemente un error en tiempo de ejecuci¢n"

}"

El constructor clase::clase() ser llamado dos veces, as¡ como tambi‚n"

el destructor clase::~clase(). El C++ no ofrece ninguna garant¡a de que"

el destructor ser llamado para un objeto creado con new, a no ser que"

se utilice delete. El programa anterior no libera nunca q, pero libera"

dos veces p. Dependiendo del tipo de p y de q, el programador puede o"

no considerar esto un error. No liberar un objeto no es normalmente un"

error, sino que se considera malgastar memoria. Liberar dos veces p es"

normalmente un error serio. El resultado t¡pico de aplicar delete al"

mismo puntero dos veces es un bucle infinito en la rutina de gesti¢n de"

almacenamiento libre, pero el comportamiento en este caso no est espe-"

cificado por la definici¢n del lenguaje y depende de la implementaci¢n."

VECTORES DE OBJETOS DE CLASE "

Para declarar un vector de objetos de una clase con un constructor, "

esa clase debe tener un constructor que pueda ser llamado sin una"

lista de argumentos. Ni siquiera pueden ser usados los argumentos"

por defecto."

EJEMPLO DE VECTORES DE OBJETOS "

#include <iostream.h>"

class cl1"

{

int x;"

public:"

cl1 (int i) { x = i; }"

int devx (void) { return x; }"

};

class cl2"

{

int x;"

public:"

cl2 (int i = 0) { x = i; }"

int devx (void) { return x; }"

};

class cl3"

{

int x;"

public:"

cl3 (void) { x = 0; }"

cl3 (int i) { x = i; }"

int devx (void) { return x; }"

};

class cl4"

{

int x;"

public:"

void asigx (int i) { x = i; }"

int devx (void) { return x; }"

};

cl1 vcl1[10]; // ilegal: error en compilaci¢n"

cl2 vcl2[10]; // ilegal: error en compilaci¢n"

cl3 vcl3[10];"

cl4 vcl4[10];"

void main (void)"

{

vcl4[6].asigx(1);"

cout << vcl3[5].devx() << " " << vcl4[6].devx(); // imprime (r)0 1¯"

}

Para vectores que no son asignados usando new, el destructor es "

llamado impl¡citamente para cada elemento del vector cuando ese"

vector es destruido. Sin embargo, esto no se puede hacer impl¡-"

citamente para vectores creados con new, ya que el compilador"

no puede distinguir el puntero a un simple objeto del puntero"

al primer elemento de un vector de objetos."

EJEMPLO DE LLAMADAS A DESTRUCTORES EN VECTORES DE OBJETOS "

#include <iostream.h>"

const int n = 3;"

class clase"

{

public:"

static int contc, contd;"

clase (void) { cout << 'c' << ++contc << ' '; }"

~clase (void) { cout << 'd' << ++contd << ' '; }"

};

int clase::contc, clase::contd;"

void f (void)"

{

clase *p = new clase;"

clase *q = new clase[n];"

delete p; // una clase"

delete q; // problema: n clases"

}

void g (void)"

{

clase *p = new clase;"

clase *q = new clase[n];"

delete p;"

delete [n] q;"

}

void h (void)"

{

clase c1;"

clase vc2[n];"

}

void main (void)"

{

clase::contc = clase::contd = 0;"

cout << '\n';"

f (); // imprime (r)c1 c2 c3 c4 d1 d2¯"

clase::contc = clase::contd = 0;"

cout << '\n';"

g (); // imprime (r)c1 c2 c3 c4 d1 d2 d3 d4¯"

clase::contc = clase::contd = 0;"

cout << '\n';"

h (); // imprime (r)c1 c2 c3 c4 d1 d2 d3 d4¯"

}

OBJETOS COMO MIEMBROS "

Los objetos (ya sean clases, estructuras o uniones), al igual "

que cualquier variable, pueden ser miembros de otros objetos."

Los constructores de los objetos miembros pueden ser invocados"

entre el nombre de la definici¢n (no declaraci¢n) del construc- "

tor del objeto y la llave de apertura de la definici¢n de la"

funci¢n constructora. Si se van a invocar varios constructores"

de objetos miembros, estas llamadas se separan por comas."

EJEMPLO DE OBJETOS COMO MIEMBROS "

/*"

Este programa imprime:"

c1_1 c1_2 c1_3 c2_1 x2_10 x1_10 x1_10 x1_10 d2_1 d1_1 d1_2 d1_32"

*/

#include <iostream.h>"

class cl1"

{

static int contc1, contd1;"

int x1;"

public:"

cl1 (int i) { x1 = i; cout << "c1_" << ++contc1 << " "; }"

~cl1 (void) { cout << "d1_" << ++contd1 << " "; }"

void impr (void) { cout << "x1_" << x1 << " "; }"

};

int cl1::contc1 = 0, cl1::contd1 = 0;"

class cl2"

{

static int contc2, contd2;"

int x2;"

cl1 a, b, c;"

public:"

cl2 (int i): a (i), b (i), c (i)"

{ x2 = i; cout << "c2_" << ++contc2 << " "; }"

~cl2 (void) { cout << "d2_" << ++contd2 << " "; }"

void impr (void) { cout << "x2_" << x2 << " "; }"

void impra (void) { a.impr (); }"

void imprb (void) { b.impr (); }"

void imprc (void) { c.impr (); }"

};

int cl2::contc2 = 0, cl2::contd2 = 0;"

"void main (void)"

{

cl2 c (10);"

c.impr ();"

c.impra ();"

c.imprb ();"

c.imprc ();"

}

/*"

Si no queremos que el constructor cl2 sea inline, har¡amos:"

class cl2"

{"

..."

public"

cl2 (int i);"

..."

};"

cl2::cl2 (int i): a (i), b (i), c (i)"

{

x2 = i;"

cout << "c2_" << ++contc2 << " ";"

}"

*/

AUTORREFERENCIA: EL PUNTERO this "

La palabra clave ~this~ denota un puntero autorreferencial declarado"

impl¡citamente. Puede ser usado en cualquier funci¢n miembro."

A todas las funciones miembros de un objeto se les pasa un argumento"

oculto: this. Este argumento impl¡cito siempre apunta al objeto para"

el cual se ha invocado la funci¢n miembro."

EJEMPLO DEL PUNTERO this "

#include <iostream.h>"

class x"

{

int a, b;"

public:"

x (int aa, int bb) { a = aa; b = bb; }"

int leera (void) { return a; } // devuelve el valor de x::a"

int leerb (void) { return this->b; } // devuelve el valor de x::b"

};

void main (void)"

{

x x (1, 2);"

cout << x.leera () << x.leerb (); // imprime (r)12¯"

}

FUNCIONES MIEMBROS CONSTANTES "

Una funci¢n miembro constante no modifica los datos miembros de un objeto.

Una funci¢n miembro constante es el £nico tipo de funci¢n miembro que

puede ser llamada por un objeto constante.

Una funci¢n miembro constante puede ser llamada tambi‚n por objetos no

constantes.

No se puede calificar una definici¢n de funci¢n con const y entonces

intentar modificar los datos miembros (esto generar un error).

Para crear una funci¢n miembro constante hay que colocar el calificador

const despu‚s de la lista de argumentos y antes de abrir la llave de

definici¢n de la funci¢n.

Las funciones miembros constantes s¢lo pueden llamar a otras funciones

miembros constantes.

Los constructores y los destructores no necesitan ser declarados funciones

miembros constantes para que sean invocados por objetos constantes.

EJEMPLO DE USO CORRECTO Y INCORRECTO DE FUNCIONES MIEMBROS CONSTANTES "

// Ejemplo de funciones miembros constantes y objetos constantes"

class clase"

{

private:"

int x;"

public:"

clase (void) { x = 0; }"

~clase () { }"

int dev (void) const { return x; } // CORRECTO: funci¢n constante no"

// modifica ning£n miembro"

void incr (void) { x++; } // CORRECTO: funci¢n miembro"

// ordinaria (no constante)"

/*"

clase (int i) const { x = i; } // ERROR: funci¢n constante"

// modificando miembro"

void incr2 (void) const { x++; } // ERROR: funci¢n constante"

// modificando miembro"

void incr3 (void) const { incr (); } // ERROR: funci¢n constante"

// llama a funci¢n no constante"

*/

};

void main (void)"

{

const clase cl1; // cl1 es un objeto constante"

cl1.dev (); // CORRECTO: funci¢n constante llamada por objeto"

// constante"

/*"

cl1.incr (); // ERROR: funci¢n no constante llamada por objeto"

// constante"

*/

clase cl2; // cl2 es un objeto ordinario (no constante)"

cl2.dev (); // CORRECTO: funci¢n constante llamada por objeto no"

// constante"

cl2.incr (); // CORRECTO: funci¢n no constante llamada por objeto no"

// constante"

}

FUNCIONES MIEMBROS VOLATILES "

Las funciones miembros vol tiles son an logas a las funciones miembros

constantes, y son creadas de la misma forma, colocando el calificador

volatile despu‚s de la lista de argumentos y antes del cuerpo de la

funci¢n.

S¢lo funciones miembros vol tiles pueden ser llamadas por objetos

vol tiles, y las funciones miembros vol tiles pueden s¢lo llamar

a otras funciones miembros vol tiles.

Al contrario que las funciones miembros constantes, las funciones

miembros vol tiles pueden modificar los datos miembros de un objeto.

Los constructores y los destructores no necesitan ser declarados

funciones miembros vol tiles para ser invocados por objetos vol tiles.

Una funci¢n miembro puede ser constante y vol til.

EJEMPLO DE USO CORRECTO Y INCORRECTO DE FUNCIONES MIEMBROS VOLATILES "

// Ejemplo de funciones miembros vol tiles y objetos vol tiles"

class clase"

{

private:"

int x;"

public:"

clase (void) { x = 0; } // constructor no vol til"

clase (int i) volatile { x = i; } // constructor vol til"

~clase () { } // destructor no vol til"

int dev (void) volatile { return x; } // funci¢n miembro vol til"

void incr (void) { x++; } // funci¢n miembro no vol til"

/*"

void incr2 (void) volatile { incr (); } // ERROR: funci¢n vol til"

// llama a funci¢n no vol til"

*/

};

void main (void)"

{

volatile clase cl1; // cl1 es un objeto vol til"

cl1.dev (); // CORRECTO: funci¢n vol til llamada por objeto"

// vol til"

/*"

cl1.incr (); // ERROR: funci¢n no vol til llamada por objeto"

// vol til"

*/

clase cl2; // cl2 es un objeto ordinario (no vol til)"

cl2.dev (); // CORRECTO: funci¢n vol til llamada por objeto no"

// vol til"

cl2.incr (); // CORRECTO: funci¢n no vol til llamada por objeto no"

// vol til"

}

ALGUNAS DECLARACIONES DE CLASES CURIOSAS "

#include <iostream.h>"

class clase1"

{

public:"

int i;"

float f;"

int devi (void) { return i; }"

float devf (void) { return f; }"

};

void f (void)"

{

clase1 c = { 10, 20.35 };"

cout << c.devi () << ' ' << c.devf () << '\n'; // imprime (r)10 20.35¯"

}

class clase2"

{

int a, b;"

public:"

clase2 (int i, int j): a (i), b (i + j) { }"

int deva (void) { return a; }"

int devb (void) { return b; }"

};

void g (void)"

{

clase2 c (1, 2);"

cout << c.deva () << ' ' << c.devb () << '\n'; // imprime (r)1 3¯"

}

class clase3"

{

int a, b;"

public:"

clase3 (int i, int j): a (i) { b = j; }"

int deva (void) { return a; }"

int devb (void) { return b; }"

};

void h (void)"

{

clase3 c (2, 3);"

cout << c.deva () << ' ' << c.devb () << '\n'; // imprime (r)2 3¯"

}

class clase4"

{

public:"

int d;"

float f;"

int devd (void) const volatile { return d; }"

float devf (void) volatile const { return f; }"

};

void i (void)"

{

clase4 c = { 2, 3.4 };"

cout << c.devd () << ' ' << c.devf () << '\n'; // imprime (r)2 3.4¯"

}

void main (void)"

{

f ();"

g ();"

" h ();"

i ();"

}

; LECCION 5

CONVERSIONES Y SOBRECARGA DE OPERADORES "

~ ~ "

~ En esta lecci¢n se estudia todo lo referente

~ a las conversiones de tipos (tanto expl¡citas

~ como impl¡citas) y la sobrecarga de operadores

~ (los operadores sobrecargados son una forma

~ corta de invocar a las funciones de operadores).

INDICE DE ESTA LECCION "

En esta lecci¢n se va a estudiar los siguientes puntos:"

- ~Conversiones tradicionales:~ notaci¢n molde y conversiones impl¡citas. "

- ~Conversiones de TAD's:~ notaci¢n funcional y conversiones impl¡citas."

- ~Algoritmo de selecci¢n de funci¢n sobrecargada:~ tres reglas."

- ~Especificador friend:~ hace funciones y clases amigas de una clase."

- ~Sobrecarga de operadores:~ palabra clave operator."

- ~Objetos grandes:~ pasarlos por referencia en los argumentos."

- ~Asignaci¢n e inicializaci¢n:~ dos conceptos diferentes."

- ~Ejemplo de sobrecarga de algunos operadores:~ (), [], ,, new y delete."

CONVERSIONES TRADICIONALES "

Las conversiones tradicionales del C++ son las conversiones de tipo que"

realiza el C, y que por lo tanto, tambi‚n las realiza el C++."

Las reglas generales de conversi¢n son las siguientes:"

ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸

³ Conversi¢n autom tica en una expresi¢n aritm‚tica x op y ³

ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵

³ ³

³ Primero: ³

³ Todo char y short son convertidos a int. ³

³ Todo unsigned char y unsigned short son convertidos a unsigned. ³

³ ³

³ Segundo: ³

³ Si despu‚s del primer paso, los dos operandos de la expresi¢n son de ³

³ tipo diferente, entonces de acuerdo a la jerarqu¡a de tipos ³

³ int < unsigned < long < unsigned long < float < double ³

³ el operando de tipo m s bajo es convertido al tipo del operando de ³

³ tipo m s alto y el valor de la expresi¢n es de ese tipo. ³

³ ³

ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

EJEMPLOS DE CONVERSIONES "

char c; short s; unsigned u; int i; long l; float f; double d;"

Expresi¢n Tipo Expresi¢n Tipo"

----------- ------- ----------- --------"

c - s / i int u * 3 - i unsigned"

u * 3.0 - i double f * 3 - i float"

c + 1 int 3 * s * l long"

c + 1.0 double d + s double"

CONVERSIONES DE TAD "

El C++ introduce la notaci¢n funcional para hacer conversiones expl¡citas de

tipo.

Una notaci¢n funcional de la forma"

nombre_tipo (expresion)"

es equivalente a la notaci¢n molde"

(nombre_tipo) (expresion)"

As¡, estas dos expresiones son equivalentes:"

x = float (i);"

x = (float) i;"

En C++ es preferible utilizar la notaci¢n funcional."

Un constructor con un argumento es de hecho una conversi¢n de tipo del tipo

del argumento al tipo de la clase del constructor.

EJEMPLO "

// Ejemplo de conversi¢n de un tipo ya definido a un tipo definido"

// por el usuario."

#include <iostream.h>"

class clase"

{

int x;"

public:"

clase (void) { x = 0; }"

clase (int i) { x = i; }"

int devx (void) { return x; }"

void imprx (void) { cout << devx () << '\n'; }"

};

void main (void)"

{

clase c1;"

clase c2 (1);"

clase c3 = clase (2); // conversi¢n de tipo expl¡cita"

clase c4 = 3; // conversi¢n de tipo impl¡cita: clase c4 = clase (3);"

clase c5 = c4; // no hay conversi¢n de tipo"

c1.imprx (); // imprime (r)0¯"

c2.imprx (); // imprime (r)1¯"

c3.imprx (); // imprime (r)2¯"

c4.imprx (); // imprime (r)3¯"

c5.imprx (); // imprime (r)3¯"

}

~Tambi‚n es posible hacer conversiones de un tipo definido por el

~usuario a un tipo definido ya.

La forma de hacer esto es incluir funciones miembros de la forma:"

operator tipo () { ... }"

EJEMPLO "

// Ejemplo de conversi¢n de un tipo definido por el usuario a un"

// tipo definido ya"

#include <iostream.h>"

class clase"

{

int x;"

public:"

clase (int i) { x = i; }"

operator int () { return x; }"

};

inline void impr (int ent) { cout << ent << '\n'; }"

void main (void)"

{

clase c1 = clase (2); // conversi¢n de tipo expl¡cita"

clase c2 = 3; // conversi¢n de tipo impl¡cita: clase c4 = clase (3);"

clase c3 = c1; // no hay conversi¢n de tipo"

int a = 1; // no hay conversi¢n de tipo"

int b = int ('a'); // conversi¢n de tipo expl¡cita"

int c = 'A'; // conversi¢n de tipo impl¡cita: int c = int ('A');"

int d = int (c2); // conversi¢n de tipo expl¡cita"

int e = c3; // conversi¢n de tipo impl¡cita: int e = int (c3)"

int f = int (clase (4)); // dos conversiones de tipo expl¡cita"

impr (a); // imprime (r)1¯"

impr (b); // imprime (r)97¯. Nota: el valor ASCII de 'a' es 97."

impr (c); // imprime (r)65¯. Nota: el valor ASCII de 'A' es 65."

impr (d); // imprime (r)3¯"

impr (e); // imprime (r)2¯"

impr (f); // imprime (r)4¯"

}

ALGORITMO DE SELECCION DE FUNCION SOBRECARGADA "

" ~1. Usa un ajuste exacto si se encuentra. ~ "

~ Un short, un char, o una constante 0 es un ajuste exacto para int.

~ Un float es un ajuste exacto para double.

" ~2. Intenta conversiones impl¡citas de tipos est ndares y usa cualquier

~ ajuste.

~ Estas conversiones no deben perder informaci¢n.

~ Dichas conversiones incluyen conversiones de puntero y las siguientes

~ extensiones: int a long y int a double.

" ~3. Intenta conversiones definidas por el usuario y usa un ajuste para el

~ cual hay un £nico conjunto de conversiones.

EJEMPLO "

"// Ejemplo de conversiones de tipos y de selecci¢n de funciones"

// sobrecargadas"

#include <iostream.h>"

class clase"

{

int x;"

public:"

clase (int i = 0) { x = i; }"

operator int () { return x; }"

};

"inline void impr (int ent) { cout << ent << '\n'; }"

inline int max (int a, int b) { return a > b ? a : b; }"

"// conversi¢n impl¡cita: { return int (a) > int (b) ? a : b; }"

inline clase max (clase a, clase b) { return a > b ? a : b; }"

"void main (void)"

{

clase c1 = 2; // conversi¢n impl¡cita: clase c1 = clase (2);"

clase c2 = clase (3); // conversi¢n expl¡cita"

" impr (max (4, 3)); // imprime (r)4¯"

" // conversi¢n expl¡cita"

impr (int (max (c1, c2))); // imprime (r)3¯."

" // conversi¢n impl¡cita: impr (int (max (c1, c2)));"

impr (max (c1, c2)); // imprime (r)3¯."

" // conversi¢n expl¡cita en max"

impr (max (int (c1), 10)); // imprime (r)10¯."

" // conversi¢n expl¡cita en max"

impr (max (c1, clase (10))); // imprime (r)10¯."

"/*"

impr (max (c1, 10));"

Esta sentencia provoca el error de compilaci¢n:"

"Ambigedad entre max(clase,clase) y max(int,int).

Se viola la tercera regla de las tres que acabamos de mencionar ya"

que el compilador no sabe qu‚ funci¢n escoger entre max(clase,clase)"

y max(int,int) para realizar la conversi¢n de tipos."

*/

// conversi¢n impl¡cita: impr (int (max (c1, c2)) + int (max (5, 6)));"

impr (max (c1, c2) + max (5, 6)); // imprime (r)9¯"

// conversi¢n impl¡cita: int (c2)."

// La conversi¢n expl¡cita int (2) es redundante."

impr (int (2) + 3 * c2); // imprime (r)11¯"

// conversiones impl¡citas: impr (int (c1 = clase (int (c2) + 2)));"

impr (c1 = c2 + 2); // imprime (r)5¯"

}

ESPECIFICADOR friend "

La palabra clave friend (amigo/a) es un especificador de funci¢n o de clase."

El especificador friend permite que una funci¢n no miembro de una clase X, u

otra clase Y, puedan acceder a los miembros privados de la clase X.

FUNCION friend "

La declaraci¢n de la funci¢n amiga debe aparecer en el interior de la"

definici¢n de la clase. La declaraci¢n de la funci¢n amiga debe empezar"

con la palabra clave friend. Esta declaraci¢n puede aparecer en la parte"

p£blica o en la parte privada de la clase sin afectar a su significado."

EJEMPLO "

// Ejemplo de funci¢n friend"

#include <iostream.h>"

class clase"

{

friend void asig (clase& cl, int i);"

friend int dev (clase cl) { return cl.x; }"

int x;"

public:"

clase (int i = 0) { x = i; }"

int devx (void) { return x; }"

};

inline void asig (clase& cl, int i) { cl.x = i; }"

void main (void)"

{

clase c (5);"

cout << dev (c) << '\n'; // imprime (r)5¯"

asig (c, -2);"

cout << c.devx () << '\n'; // imprime (r)-2¯"

}

FUNCION MIEMBRO friend "

"Las funciones miembros de una clase Y pueden ser funciones amigas de otra "

"clase X. En este caso es necesario utilizar el operador de resoluci¢n de"

" mbito en la declaraci¢n de la funci¢n amiga dentro de la clase X."

EJEMPLO "

"// Ejemplo de funci¢n miembro friend"

"#include <iostream.h>"

"class clase_B; // declarac. (no definic.) para que sea conocida en clase_A"

"class clase_A"

{

" public:"

" int dev (clase_B cl);"

};

"class clase_B"

{

" friend int clase_A::dev (clase_B cl);"

" int x;"

" public:"

" clase_B (int i = 0) { x = i; }"

" int devx (void) { return x; }"

};

"inline int clase_A::dev (clase_B cl) { return cl.x; }"

"void main (void)"

{

" clase_B c1 (5);"

" clase_A c2;"

" cout << c1.devx () << '\n'; // imprime (r)5¯"

" cout << c2.dev (c1) << '\n'; // imprime (r)5¯"

}

CLASE friend "

"Si todas las funciones miembros de una clase son funciones amigas de otra "

"clase, se dice que una clase es amiga (friend) de otra. La declaraci¢n es"

" friend class nombre_de_clase"

"en lugar de"

" friend declaracion_de_funcion"

EJEMPLO "

"// Ejemplo de clase friend"

"#include <iostream.h>"

"class clase_B; // declarac. (no definic.) para que sea conocida en clase_A"

"class clase_A"

{

" friend clase_B;"

" int x;"

" public:"

" clase_A (int i = 0) { x = i; }"

" int devx (void) { return x; }"

};

"class clase_B"

{

" public:"

" int dev (clase_A cl) { return cl.x; }"

};

"void main (void)"

{

" clase_A c1 (5);"

" clase_B c2;"

" cout << c1.devx () << '\n'; // imprime (r)5¯"

" cout << c2.dev (c1) << '\n'; // imprime (r)5¯"

}

SOBRECARGA DE OPERADORES "

"Los operadores se pueden sobrecargar al igual que las funciones. La uti-"

"lizaci¢n de operadores sobrecargados conduce a programas m s cortos y m s"

"legibles."

"Hemos utilizado anteriormente la palabra clave ~operator~ para definir una "

"funci¢n miembro que realiza la conversi¢n de tipos. Tambi‚n puede usarse"

"esta palabra clave para sobrecargar operadores de C++."

"Aunque se sumen nuevos significados a los operadores, su asociatividad y"

"precedencia se conserva. Tampoco se puede cambiar la sintaxis de operadores,"

"por ejemplo, no es posible definir un operador unario % o uno binario !."

"Los operadores que no pueden ser sobrecargados son:"

" - operador de selector de componente (.)"

" - operador de referencia a trav‚s de un puntero a un miembro (.*)"

" - operador de resoluci¢n/acceso de mbito (::)"

" - operador condicional (?:)"

"Los operadores de autoincremento y autodecremento, ++ y --, se pueden sobre-"

"cargar pero sus significados en notaci¢n prefija y postfija es el mismo en"

"la forma sobrecargada."

"Todos los dem s operadores se pueden sobrecargar, ‚stos incluyen:"

" - operadores aritm‚ticos - operadores de bits"

" - operadores l¢gicos - operador de indexado []"

" - operadores de comparaci¢n - llamada a funci¢n ()"

" - operadores de igualdad - operadores new y delete"

" - operadores de asignaci¢n"

"No es posible definir nuevos tokens de operadores, pero se puede usar la"

"notaci¢n de llamada a funci¢n cuando este conjunto de operadores es ina-"

"decuado. Por ejemplo, usa pow() en vez de **."

"El ; no se puede sobrecargar puesto que no es un operador."

FUNCION OPERADOR (operator) "

" ~El nombre de una funci¢n operador es la palabra clave operator seguida por

" ~el operador.~ Por ejemplo, operator<<. Una funci¢n operador es declarada"

" como cualquier otra funci¢n y por lo tanto puede ser llamada como cualquier"

" otra; el uso del operador es solamente una forma corta de escribir una"

" llamada expl¡cita de una funci¢n de operador. Por ejemplo, definida una"

" clase complex en la cual se ha definido un operador de suma, las dos ini-"

" cializaciones siguientes son sin¢nimas."

" void f (complex a, complex b)"

" {"

" complex c = a + b; // forma corta"

" complex d = operator+ (a, b), // llamada expl¡cita"

" }"

OPERADORES BINARIOS Y UNARIOS "

Hay dos formas de sobrecargar los operadores: haciendo que sean funciones

miembros o haciendo que sean funciones amigas.

"Un operador binario puede ser definido bien usando una funci¢n que toma"

"un argumento o bien usando una funci¢n amiga que toma dos argumentos."

"As¡, para cualquier operador binario @, a@b puede ser interpretado bien"

"como a.operator@(b) o bien como operator@(a,b). Si ambos est n definidos,"

"a@b es un error."

"Un operador unario, ya sea prefijo o postfijo, puede ser definido bien"

"usando una funci¢n miembro que no toma ning£n argumento o bien usando"

"una funci¢n amiga que toma un argumento. As¡, para cualquier operador @,"

"tanto a@ como @a puede ser interpretado bien como a.operator@() o bien"

"como operator@(a). Si ambos est n definidos, a@ y @a son errores."

"Considerar este ejemplo:"

" class X"

" {"

" // funciones amigas:"

" friend X operator- (X); // menos unario"

" friend X operator- (X,X); // menos binario"

" friend X operator- (); // error: no hay operando"

" friend X operator- (X,X,X); // error: ternario"

" // funciones miembros (con primer argumento impl¡cita: this):"

" X *operator& (); // unario & (direcci¢n de)"

" X operator& (X); // binario & (and a nivel de bits)"

" X operator& (X,X); // error: ternario"

" };"

EJEMPLO "

"// Ejemplo de operadores sobrecargados."

"#include <iostream.h>"

"class clase"

{

" friend clase operator- (clase c1, clase c2);"

" friend clase operator- (clase cl) { return 0 - cl; }"

" friend clase operator/ (clase, clase);"

" private:"

" int x, y;"

" public:"

" clase (int xx = 0, int yy = 0) { x = xx; y = yy; }"

" int getx (void) { return x; }"

" int gety (void) { return y; }"

" clase operator+ (clase cl) { return *this - -cl; }"

" clase operator+ (void) { return *this; }"

" clase operator* (clase);"

};

"inline clase operator- (clase c1, clase c2)"

{

" return clase (c1.getx () - c2.getx (), c1.gety () - c2.gety ());"

}

"inline clase operator/ (clase c1, clase c2)"

{

" return clase (c1.getx () / c2.getx (), c1.gety () / c2.gety ());"

}

"inline clase clase::operator* (clase cl)"

{

" return clase (this->getx () * cl.getx (), this->gety () * cl.gety ());"

}

"inline void escribir (clase c)"

{

" cout << c.getx () << ' ' << c.gety () << '\n';"

}

"void main (void)"

{

" clase c1 (5), c2 (2, 3);"

" escribir (c1 - c2); // imprime (r)-3 -3¯"

" escribir (c1 + c2); // imprime (r)7 3¯"

" escribir (-c1 - +c2); // imprime (r)-7 -3¯"

" escribir (c1 / c2 + c2 * c1); // imprime (r)12 0¯"

" clase c3 = c1 + c2 + c2;"

" escribir (c3 * c3); // imprime (r)81 36¯"

}

SIGNIFICADOS PREDEFINIDOS PARA LOS OPERADORES "

No se hace ninguna asunci¢n acerca del significado de un operador definido

por el usuario.~ En particular, puesto que un = sobrecargado no se asume para"

"implementar la asignaci¢n del segundo operando al primer operando, no se"

"testea para asegurar que el primer operando es un lvalue (un lvalue es una"

"direcci¢n que aparece en el lado izquierdo de una sentencia de asignaci¢n y"

"a la cual se le puede dar un valor). El significado de algunos operadores ya"

"construidos est n definidos para ser equivalentes a alguna combinaci¢n de"

"otros operadores sobre los mismos argumentos. Por ejemplo, si a es un int,"

"++a significa a+=1, y esto significa a su vez a=a+1. En los operadores defi-"

"nidos por el usuario tales equivalencias no son ciertas (a no ser que el"

"usuario defina estos operadores de esa forma). ~Los operadores = y & tienen

significados predefinidos cuando se aplican a objetos de clases.~ No hay una"

"forma elegante de "indefinir" estos dos operadores. Puede ser, sin embargo,"

"inhabilitados para una clase X. Se puede declarar, por ejemplo, X::operator&"

"() sin proporcionar una definici¢n para ‚l. Si en alg£n lugar se toma la"

"direcci¢n de un objeto de la clase X, el enlazador detectar la ausencia de"

"la definici¢n. En algunos sistemas esta t‚cnica no puede ser usada porque el"

"enlazador es tan "inteligente" que detecta que hay una funci¢n declarada y"

"no definida aun cuando tal funci¢n no se use. Por ello, una soluci¢n alter-"

"nativa es definir la funci¢n X::operator&() para que provoque un error en"

"tiempo de ejecuci¢n."

UNA CLASE DE NUMEROS COMPLEJOS (clase complex) "

"Las funciones de operadores, al igual que todas las funciones,"

"se pueden sobrecargar. Por ejemplo:"

" class complex"

" {"

" double re, im;"

" public:"

" complex (double r, double i) { re = r; im = i; }"

" friend complex operator+ (complex, complex);"

" friend complex operator+ (complex, double);"

" friend complex operator+ (double, complex);"

" friend complex operator- (complex, complex);"

" friend complex operator- (complex, double);"

" friend complex operator- (double, complex);"

" complex operator- ();"

" friend complex operator* (complex, complex);"

" friend complex operator* (complex, double);"

" friend complex operator* (double, complex);"

" // ..."

" };"

" void f (void)"

{

" complex a (1, 1), b (2, 2), c (3, 3), d (4, 4), e (5, 5);"

" a = -b - c;"

" b = c * 2.0 * c;"

" c = (d + e) * a;"

" }"

"Para evitar escribir tres funciones sobrecargadas para cada"

"operador binario, declaramos un constructor que, dado un double"

"cree un complex. Por ejemplo:"

" class complex"

" {"

" // ..."

" complex (double r) { re = r; im = 0; }"

" };"

"Ahora podemos hacer:"

" complex z1 = complex (23);"

" complex z2 = 23;"

"donde, tanto z1 como z2, ser n inicializados llamando a"

"complex(23,0)."

"La clase complex la podemos declarar de esta nueva forma:"

" class complex"

" {"

" double re, im;"

" public:"

" complex (double r, double i = 0) { re = r; im = i; }"

" friend complex operator+ (complex, complex);"

" friend complex operator* (complex, complex);"

" };"

"y deber¡an ser legales las operaciones que involucren variables"

"complex y constantes enteras. Una constante entera ser inter-"

"pretada como complex con la parte imaginaria cero. Por ejemplo,"

" a = b * 2"

"significa"

" a = operator+ (b, complex (double (2), double (0)))"

"Una conversi¢n definida por el usuario es aplicada impl¡cita-"

"mente £nicamente si es £nica."

"Un objeto construido por el uso expl¡cito o impl¡cito de un"

"constructor es autom tico y ser destruido en la primera opor-"

"tunidad, normalmente inmediatamente despu‚s de la sentencia en"

"la cual fue creado."

OPERADORES # Y ## DEL PREPROCESADOR "

"No se pueden sobrecargar los operadores # y ## porque son operadores del"

"preprocesador de C++, no del lenguaje C++. Los operadores almohadilla (#)"

"y doble almohadilla (##) ejecutan sustituciones y fusionado de tokens en"

"la fase de exploraci¢n del preprocesador."

"El operador unario # convierte (sustituye) el token de su operando en"

"string. El operador binario ## fusiona dos tokens (operando izquierdo"

"y operando derecho en un s¢lo token."

"El s¡mbolo # tambi‚n se utiliza para indicar una directiva del prepro-"

"cesador, pero en este caso no act£a como operador."

"El siguiente ejemplo muestra c¢mo se utilizan los operadores # y ## del"

"preprocesador."

EJEMPLO "

"// Ejemplo de los operadores # y ## del preprocesador de C++."

"#include <iostream.h>"

"#define impr_suma(x) cout << #x " + " #x " = " << x + x << "\n

"#define var(x,y) (x##y)"

"void main (void)"

{

" int x1;"

" var (x, 1) = 5;"

" cout << "Ejemplo" " de los " "operadores # y ## del "

" "preprocesador:\n";"

" impr_suma (x1);"

" impr_suma (100);"

}

"/*"

"SALIDA DEL PROGRAMA:"

"Ejemplo de los operadores # y ## del preprocesador:"

"x1 + x1 = 10"

"100 + 100 = 200"

*/

OBJETOS GRANDES "

" Cuando se pasa un objeto como ~argumento por valor~ a una "

" funci¢n, se est pasando, en realidad, una copia de ese"

" objeto. En objetos de cierto tama¤o es deseable evitar"

" tanto traspaso de informaci¢n. Esto se consigue pasando"

" los objetos como ~argumento por referencia~ a las funcio-"

" nes. Para ello utilizamos el operador de referencia ~&~."

ASIGNACION E INICIALIZACION "

"Consideremos una clase string muy simple:"

" struct string"

" {"

" char *p;"

" int size; // tama¤o del vector apuntado por p"

" string (int sz) { p = new char[size = sz]; }"

" ~~string () { delete p; }"

" };"

"Un string es una estructura de datos compuesta de un puntero a un vector"

"de caracteres y el tama¤o de ese vector. El vector es creado por el cons-"

"tructor y borrado por el destructor. Sin embargo, tal y como est cons-"

"truida la clase string puede causar problemas. Por ejemplo:"

" void f (void)"

{

" string s1 (10);"

" string s2 (20);"

" s1 = s2;"

" }"

"asignar dos vectores de caracteres, pero la asignaci¢n s1 = s2 har que"

"el puntero p de s1 apunte al mismo sitio que el puntero p de s2. Cuando"

"sean invocados los destructores s1 y s2, se destruir dos veces el mismo"

"vector con resultados desastrosos impredecibles. La soluci¢n a este pro-"

"blema es definir apropiadamente la asignaci¢n de los objetos string."

"La asignaci¢n por defecto entre objetos es la copia de elementos"

"de uno a otro. Definamos un nuevo operador de asignaci¢n a nuestra"

"clase string para resolver el problema planteado:"

" struct string"

" {"

" char *p;"

" int size; // tama¤o del vector apuntado por p"

" string (int sz) { p = new char[size = sz]; }"

" ~~string () { delete p; }"

" void operator= (string&);"

" };"

" void string::operator= (string& a)"

{

" if (this == &a) return; // previene s = s"

" delete p;"

" p = new char[size = a.size];"

" strcpy (p, a.p);"

" }"

"Con la nueva definici¢n de string aseguramos que el ejemplo"

"anterior (funci¢n f()) trabajar correctamente. Sin embargo,"

"todav¡a hay un problema latente que lo podemos observar si"

"hacemos una peque¤a modificaci¢n en f():"

" void f (void)"

{

" string s1 (10);"

" string s2 = s1;"

" }"

"Ahora s¢lo un string es construido pero dos son destruidos."

"Los operadores de asignaci¢n definidos por el usuario no son"

"aplicados a objetos no inicializados. Un r pido vistazo a"

"string::operator=() muestra porqu‚ esto es as¡: el puntero"

"p contendr¡a un valor indefinido (aleatorio). Consecuente-"

"mente, debemos definir otra funci¢n miembro adicional para"

"hacer frente a la inicializaci¢n."

"La nueva definici¢n de string para tener en cuenta la"

"inicializaci¢n es:"

" struct string"

" {"

" char *p;"

" int size; // tama¤o del vector apuntado por p"

" string (int sz) { p = new char[size = sz]; }"

" ~~string () { delete p; }"

" void operator= (string&);"

" };"

" void string::string (string& a)"

{

" p = new char[size = a.size];"

" strcpy (p, a.p);"

" }"

"Para un tipo X, el constructor X(X&) proporciona la inicializaci¢n para un"

"objeto del mismo tipo X. Las operaciones de asignaci¢n y de inicializaci¢n"

"son diferentes; pero s¢lo tiene especial importancia tal diferencia cuando"

"una clase X tiene un destructor que realiza tareas no triviales, tales co-"

"mo desasignaci¢n de memoria, en cuyo caso es deseable evitar la copia ele-"

"mento a elemento de objetos:"

" class X"

" {"

" // ..."

" X (algo); // constructor: crea objetos"

" X (X&); // constructor: copia en inicializaci¢n"

" operator= (X&); // asignaci¢n: borrado y copia"

" ~~X (); // destructor: borrado"

" };"

"Hay dos casos m s en los que un objeto es copiado: como un argumento de"

"funci¢n y como un valor devuelto por una funci¢n. En ambos casos se crea"

"una variable que es inicializada con el objeto del argumento o con el"

"objeto a devolver; en ambos casos se llamar , por tanto, a la funci¢n"

"X(&X) si ‚sta est definida:"

" string g (string arg)"

{

" return arg;"

" }"

" void main (void)"

{

" string s = "asdf";"

" s = g (s);"

" }"

"Claramente, el valor de s deber¡a ser "asdf" despu‚s de la llamada a"

"g(). El argumento arg se convierte en una copia del valor de s llamando"

"a string::string(string&). El valor devuelto por g() es una copia del"

"valor de arg creada llamando a string::string(string&); esta vez, la"

"variable inicializada es una variable temporal, la cual es asignada a"

"s. Tales variables temporales son destruidas, usando string::~string(),"

"tan pronto como es posible."

EJEMPLO DE SOBRECARGA DE ALGUNOS OPERADORES "

"#include <iostream.h> // cout"

"#include <stddef.h> // size_t"

"class clase"

{

" public:"

" int x, y, sum, dif, prod;"

" clase (int i, int j): x (i), y (j), sum (i + j),"

" dif (i -j), prod (x * y) {}"

" void escr (const char *s)"

" {"

" cout << "\n" << s << ": x = " << x << " y = " << y << " sum = " << sum"

" << " dif = " << dif << " prod = " << prod;"

}

" operator int () { return dif; }"

" int operator () (void) { return prod; }"

" int operator [] (int ind)"

" { return ind == 0 ? sum : ind == 1 ? prod : 0; }"

" // cambia prioridad de operador , para la clase"

" clase operator, (clase) { return *this; }"

" void *operator new (size_t)"

" {"

" cout << "\nERROR: no se puede aplicar el operador new a un objeto

" "de clase.";"

" return 0;"

}

" void operator delete (void *) { }"

};

"void main (void)"

{

" clase cl1 (1, 2), cl2 (2, 3), cl3 (3, 4);"

" int a = cl1, b = cl2 (), c = cl3 [1];"

" cout << "\n** Inicializando: clase cl1 (1, 2), cl2 (2, 3), cl3 (3, 4);

" "\n int a = cl1, b = cl2 (), c = cl3 [1];";"

" cl1.escr ("cl1");"

" cl2.escr ("cl2");"

" cl3.escr ("cl3");"

" cout << "\na = " << a << " b = " << b << " c = " << c;"

" a = (b, c, 5);"

" cl1 = (cl2, cl3, clase (5, 5));"

" cout << "\n** Ejecutando: a = (b, c, 5); cl1 = (cl2, cl3, clase (5, 5));";"

" cout << "\na = " << a;"

" cl1.escr ("cl1");"

" cout << "\n** Ejecutando: clase *pclase = new clase;";"

" clase *pclase = new clase (0, 0);"

" cout << "\n** Ejecutando: delete *pclase;";"

" delete pclase;"

" cout << "\n";"

}

"/*"

"SALIDA DE ESTE PROGRAMA:"

"** Inicializando: clase cl1 (1, 2), cl2 (2, 3), cl3 (3, 4);"

" int a = cl1, b = cl2 (), c = cl3 [1];"

"cl1: x = 1 y = 2 sum = 3 dif = -1 prod = 2"

"cl2: x = 2 y = 3 sum = 5 dif = -1 prod = 6"

"cl3: x = 3 y = 4 sum = 7 dif = -1 prod = 12"

"a = -1 b = 6 c = 12"

"** Ejecutando: a = (b, c, 5); cl1 = (cl2, cl3, clase (5, 5));"

"a = 5"

"cl1: x = 2 y = 3 sum = 5 dif = -1 prod = 6"

"** Ejecutando: clase *pclase = new clase;"

"ERROR: no se puede aplicar el operador new a un objeto de clase."

"** Ejecutando: delete *pclase;"

*/

; LECCION 6

HERENCIA SIMPLE "

Esta lecci¢n describe los conceptos de herencia y clases derivadas en

C++. Herencia es el mecanismo de derivar una nueva clase de otra vieja

clase. Esto es, una clase puede adquirir todas las caracter¡sticas de

otra clase. A la nueva clase se le llama clase derivada y a la vieja

clase se le llama clase base. Las clases derivadas proporcionan un

mecanismo simple, flexible y eficiente para especificar una interface

alternativa para una clase y para definir una clase a¤adiendo facili-

dades a una clase que ya existe sin reprogramaci¢n ni recompilaci¢n.

La herencia es una caracter¡stica importante de la programaci¢n orien-

tada a objeto.

"En los primeros est ndares de C++, una clase derivada s¢lo pod¡a here-"

"dar la descripci¢n de una clase base (herencia simple). En los nuevos"

"est ndares, una clase derivada puede tener varias clases bases (heren-"

"cia m£ltiple). En esta lecci¢n estudiaremos la herencia simple y en la"

"siguiente veremos la herencia m£ltiple."

INDICE DE ESTA LECCION "

"****************************************************************************"

"En esta lecci¢n se va a estudiar los siguientes puntos:"

"- ~Clases derivadas:~ son clases que derivan de otras clases llamadas bases."

"- ~Modificadores de acceso public, private y protected:~ estudio completo."

"- ~Punteros a clases derivadas:~ clase derivada es un subtipo de clase base."

"- ~Funciones virtuales:~ funciones declaradas con el especificador virtual."

"- ~Funciones puras:~ son clases virtuales sin definici¢n en clases bases."

"- ~Clases abstractas:~ son las clases que tienen al menos una funci¢n pura."

"- ~Jerarqu¡a de clases:~ una clase derivada puede ser tambi‚n una clase base."

"****************************************************************************"

CLASES DERIVADAS "

"Una clase puede ser derivada de una clase existente usando la foma:"

(class | struct) nombre_clase_derivada: [public | private] nombre_clase_base

{

declaracion_de_los_miembros

};

"donde (class | struct) quiere decir que en ese lugar debe ir obligatoria-"

"mente la palabra clave ~class~ o la palabra clave ~struct~; y [public | private]"

"quiere decir que en ese lugar puede ir opcionalmente los modificadores de"

"acceso ~public~ o ~private~. Si no aparece ninguno de los dos modificadores de"

"acceso, se considerar , por defecto, public para struct y private para class"

"Por ejemplo,"

" struct d : b { ..."

"significa"

" class d : public b { public: ..."

"y viceversa,"

" class b : b { ..."

"significa"

" struct b: private b { private: ..."

"Ejemplo de clase derivada:"

" class empleado"

" {"

" public:"

" char *nombre;"

" short edad;"

" short departamento;"

" int salario;"

" void imprimir (void);"

" };"

" class director: public empleado"

" {"

" public:"

" int num_empleados;"

" short tipo_director;"

" };"

"La clase director es una clase derivada de la clase empleado, y por con-"

"siguiente, la clase empleado es una clase base para la clase director."

"La clase director tiene todos los miembros p£blicos de la clase empleado"

"(nombre, edad, etc.) que son a¤adidos a los dos que ya posee la clase"

"director. Por lo tanto, la clase empleado tiene cinco miembros y la clase"

"director tiene siete."

"Si no utiliz ramos la herencia, har¡amos:"

" class director"

" {"

" public:"

" empleado empl;"

" int num_empleados;"

" short tipo_director;"

" };"

"Esta segunda versi¢n de la clase director no es equivalente a la primera."

"En la primera versi¢n, la clase director tiene siete miembros, en la se-"

"gunda tiene tres, donde el miembro empl tiene a su vez cinco miembros."

"Desde el punto de vista l¢gico, en esta segunda versi¢n no podemos decir"

"que un director es un empleado, sino m s bien que empleado es una parte"

"de director. Hay otras diferencias como las conversiones de punteros a"

"las clases empleado y director que se explicar n m s adelante."

"En el ejemplo de los directores y empleados, la forma natural de imple-"

"mentarlo en C++ es utilizando la herencia puesto que un director es un"

"empleado y posee todas las caracter¡sticas de los empleados."

MODIFICADORES DE ACCESO public, private Y protected "

"Los miembros de una clase pueden adquirir atributos de acceso de dos formas:"

"por defecto, o a trav‚s del uso de los especificadores de acceso public,"

"private y protected. La forma de utililizar estos especificadores es:"

" ~public: <declaraciones>

" ~private: <declaraciones>

" ~protected: <declaraciones>

"Los especificadores de acceso (tambi‚n llamados modificadores de visibili-"

"dad) pueden ser usados, dentro de una declaraci¢n de clase, en cualquier"

"orden y en cualquier frecuencia. El estilo usual es:"

" ~class clase

" ~ {

" ~ private: // opcional

" ~ ...

" ~ protected:

" ~ ...

" ~ public:

" ~ ...

" ~ };

"Si un miembro es ~public~, puede ser usado por cualquier funci¢n. En C++,"

"los miembros de un struct o union son public por defecto. Se puede cam-"

"biar el acceso de struct por defecto con private y protected; no se"

"puede cambiar el acceso de union por defecto."

"Si un miembro es ~private~, s¢lo puede ser usado por funciones miembros y"

"amigas de la clase en la que est declarada. Los miembros de una clase"

"son private por defecto."

"Si un miembro es ~protected~, su acceso es el mismo que para private. Pero"

"adem s el miembro puede ser usado por funciones miembros y amigas de las"

"clases derivadas de la clase declarada, pero s¢lo en objetos del tipo"

"derivado."

"Las declaraciones de ~friend~ no son modificadas por estos especificadores"

"de acceso."

"Una clase base puede ser public o private con respecto a una clase"

"derivada. Si la clase base es public, los miembros public y protec-"

"ted de la clase base conservan la misma visibilidad en la clase de-"

"rivada. Si la clase base es private, los miembros public y protected"

"de la clase base son miembros private en la clase derivada. Una cla-"

"se base en C++ puede ser public o private, pero no protected. El si-"

"guiente esquema resume todo lo dicho en este p rrafo:"

Acceso en clase base Modificador de acceso Acceso heredado de base

-------------------- --------------------- -----------------------

public public public

private public no accesible

protected public protected

-------------------- --------------------- -----------------------

public private private

private private no accesible

protected private private

"// Ejemplo sobre los especificadores de acceso en la herencia de C++"

"class base"

" {"

" private:"

" int base_priv;"

" protected:"

" int base_prot;"

" public:"

" int base_publ;"

};

"class derpubl : public base"

" {"

" private:"

" int derpubl_priv;"

" protected:"

" int derpubl_prot;"

" public:"

" int derpubl_publ;"

};

"class derpriv : private base"

" {"

" private:"

" int derpriv_priv;"

" protected:"

" int derpriv_prot;"

" public:"

" int derpriv_publ;"

};

"void main (void)"

{

" base cbase;"

" derpubl cderpubl;"

" derpriv cderpriv;"

" cbase.base_priv = 0; // error"

" cbase.base_prot = 0; // error"

" cbase.base_publ = 0; // correcto"

" cderpubl.base_priv = 0; // error"

" cderpubl.base_prot = 0; // error"

" cderpubl.base_publ = 0; // correcto"

" cderpubl.derpubl_priv = 0; // error"

" cderpubl.derpubl_prot = 0; // error"

" cderpubl.derpubl_publ = 0; // correcto"

" cderpriv.base_priv = 0; // error"

" cderpriv.base_prot = 0; // error"

" cderpriv.base_publ = 0; // error"

" cderpriv.derpriv_priv = 0; // error"

" cderpriv.derpriv_prot = 0; // error"

" cderpriv.derpriv_publ = 0; // correcto"

}

" ~La clase derivada tiene sus propios constructores, los

" ~cuales invocar n a los constructores de la clase base.

" Hay una sintaxis especial para pasar argumentos desde"

" el constructor de la clase derivada al constructor de"

" la clase base:"

" cabecera_funcion: nombre_clase_base (lista_de_argumentos)"

" En esta sintaxis nombre_clase_base es opcional pero es"

" aconsejable ponerlo siempre."

"// Ejemplo de clase derivada y clase base con constructores."

"#include <iostream.h>"

"class base"

" {"

" private:"

" int b;"

" public:"

" base (int i = 0) { b = i; }"

" int devb (void) { return b; }"

};

"class derivada : public base"

{

" private:"

" int d;"

" public:"

" derivada (int i = 0): base (i) { d = i; }"

" derivada (int i, int j);"

" int devd (void) { return d; }"

"};"

"derivada::derivada (int i, int j): base (j) { d = i; }"

"void main (void)"

{

" base cb (2);"

" derivada cd (3, 4);"

" cout<<cb.devb()<<' '<<cd.devd()<<' '<<cd.devb(); // imprime (r)2 3 4¯"

}

" ~Los miembros de una clase derivada pueden tener los

" ~mismos nombres de su clase base, pero ser n miembros

" ~diferentes aunque tengan los mismos nombres.

" En este caso se puede distinguir entre los miembros"

" de una clase y otra utilizando el operador de reso-"

" luci¢n de mbito (::)."

"// Ejemplo de miembros con el mismo nombre en clases base y derivada."

"#include <iostream.h>"

"class base"

" {"

" protected:"

" int x;"

" public:"

" base (int i = 0) { x = i; }"

" int dev (void) { return x; }"

};

"class derivada : public base"

{

" protected:"

" int x;"

" public:"

" derivada (int i = 0): base (3 * i) { x = i; }"

" int dev (void) { return x; }"

" int f (void) { return x + derivada::x + base::x; }"

" int g (void) { return dev() + derivada::dev() + base::dev(); }"

"};"

"void main (void)"

{

" derivada clase (2);"

" cout << clase.dev() << ' ' << clase.derivada::dev() << ' '"

" << clase.base::dev() << ' ' << clase.f () << ' ' << clase.g ();"

" // imprime: (r)2 2 6 10 10¯"

}

El orden de las llamadas de los constructores es: cons-

tructor de la clase base, constructores de los miembros,

y constructor de la propia clase derivada.

Los destructores son invocados en el orden contrario:

destructor de la propia clase derivada, destructor de

los miembros, y destructor de la clase base.

"// Ejemplo sobre el orden de llamada de los constructores y los"

"// destructores."

"#include <iostream.h>"

"class a"

{

" public:"

" a () { cout << "\nConstructor de la clase a"; }"

" ~a () { cout << "\nDestructor de la clase a"; }"

};

"class b"

{

" public:"

" b () { cout << "\nConstructor de la clase b"; }"

" ~b () { cout << "\nDestructor de la clase b"; }"

};

"class c : public a"

{

" private:"

" b claseb;"

" public:"

" c () { cout << "\nConstructor de la clase c"; }"

" ~c () { cout << "\nDestructor de la clase c"; }"

};

"void main (void)"

{

" c clasec;"

}

"/*"

" SALIDA DEL PROGRAMA:"

" Constructor de la clase a"

" Constructor de la clase b"

" Constructor de la clase c"

" Destructor de la clase c"

" Destructor de la clase b"

" Destructor de la clase a"

*/

Hemos dicho que cuando una clase derivada tiene una

clase base privada, todos los miembros protegidos y

p£blicos de la clase base son privados en la clase

derivada. A veces es deseable que algunos de estos

miembros sean p£blicos o protegidos en la clase de-

rivada pero manteniendo la clase base privada.~ La"

"forma de hacerlo se ilustra en el siguiente ejemplo."

"// Ejemplo sobre la conversi¢n de la visibilidad de los miembros de"

"// la clase base dentro de la clase derivada."

"class b"

{

" public: int x, y, z, f(), g(), h();"

};

"class d : private b"

{

" private: int b::x, b::f; // opcional: esta l¡nea es redundante"

" protected: int b::y, b::g; // y y g son convertidos a protected"

" public: int b::z, b::h; // z y y son convertidos a public"

};

"void main (void)"

{

" b cb;"

" d cd;"

" cb.x = cb.y = cb.z = 0; // correcto"

" cd.x = 0; // error: d::x no es accesible"

" cd.y = 0; // error: d::y no es accesible"

" cd.z = 0; // correcto"

}

" De la misma forma, ~un miembro transmitido

" ~p£blicamente puede ser convertido expl¡ci-

" ~tamente a private o protected.

"// Ejemplo sobre la conversi¢n de la visibilidad de miembros transmitidos"

"// p£blicamente de la clase base a la clase derivada."

"class b"

{

" private: int x, f();"

" protected: int y, g();"

" public: int z, h();"

};

"class d : public b"

{

" public: int b::x, b::f;// x y f convertidos de private a public"

" private: int b::y, b::g;// y y g convertidos de protected a private"

" protected: int b::z, b::h;// z y h convertidos de public a protected"

};

"void main (void)"

{

" b cb;"

" d cd;"

" cb.x = 0; // error: b::x no es accesible"

" cd.x = 0; // correcto"

" cb.z = 0; // correcto"

" cd.z = 0; // error: d::z no es accesible"

}

este borde es necesario debido a partir

PUNTEROS "

Una clase derivada p£blicamente es un subtipo de su clase base.

"Si una clase derivada tiene una clase base p£blica, entonces un puntero a la"

"clase derivada puede ser asignado a una variable de tipo puntero a la clase"

"base sin hacer uso de la conversi¢n de tipo expl¡cita. Por ejemplo:"

" void main (void)"

{

" class base { /* ... */ };"

" class derivada: public base { /* ... */ };"

" derivada d;"

" base *pb = &d; // conversi¢n impl¡cita"

" derivada *pd = pb; // error: un base* no es un derivada*"

" pd = (derivada *) pb; // conversi¢n expl¡cita"

" }"

En otras palabras, un objeto de una clase derivada puede ser tratado como

un objeto de su clase base cuando se manipula a trav‚s de punteros. Lo con-

trario no es cierto.

" \ \ \ \ / / / /"

" \ \ \ / / /"

" \ \ \ / / /"

"\ \ \ \ / / / /"

" \ Cuando la clase base es privada para la clase derivada, /"

" \ no se hace conversi¢n impl¡cita de derivada* a base*. /"

" \ Una conversi¢n impl¡cita no puede ser ejecutada en este /"

" caso porque un miembro p£blico de la clase base puede"

" / ser accedido a trav‚s de un puntero a la clase base pero \"

" / no a trav‚s de un puntero a la clase derivada. \"

" / / / / \ \ \ \"

"/ / / / \ \ \ \"

" / / / \ \ \"

" / / / \ \ \"

" / / / / \ \ \ \"

" / / / / \ \ \ \"

"// Ejemplo de puntero a clases base y derivada."

"class base"

{

" int b1;"

" public: int b2; // b2 es un miembro p£blico de base"

};

"class derivada: base"

{

" // b2 NO es un miembro p£blico de derivada"

};

"void main (void)"

{

" derivada d;"

"// Para probar error, escribir en esta l¡nea: #define PROBAR_ERROR"

"#ifdef PROBAR_ERROR"

" d.b2 = 2; // error: b2 de clase base privada"

" base *pb = &d; // error (base privada)"

"#else"

" base *pb;"

"#endif"

" pb->b2 = 2; // correcto"

" pb = (base *) &d; // correcto: conversi¢n expl¡cita"

" pb->b2 = 2; // correcto"

}

"\---------------------------------|--------------------------------/"

"||\-------------------------------|------------------------------/||"

"||||\-----------------------------|----------------------------/||||"

"||||||\---------------------------|--------------------------/||||||"

"||||||||\-------------------------|------------------------/||||||||"

"||||||||||\-----------------------|----------------------/||||||||||"

"|||||~ Entre otras cosas, el ejemplo visto muestra que usando ~|||||"

"|||||~ conversi¢n de tipo expl¡cita se pueden romper las reglas ~|||||"

"-----~ de protecci¢n. Est claro que no se recomienda hacer tal ~-----"

"|||||~ cosa en un programa a menos que se tenga la intenci¢n de ~|||||"

"|||||~ hacerlo ilegible. ~|||||"

"||||||||||/-----------------------|----------------------\||||||||||"

"||||||||/-------------------------|------------------------\||||||||"

"||||||/---------------------------|--------------------------\||||||"

"||||/-----------------------------|----------------------------\||||"

"||/-------------------------------|------------------------------\||"

"/---------------------------------|--------------------------------\"

FUNCIONES VIRTUALES "

"Hemos explicado que cuando se invoca a una funci¢n miembro sobrecargada,"

"el compilador selecciona la funci¢n de acuerdo a un algoritmo de ajuste"

"de tipos. Por ejemplo:"

" ~class c

" ~ {

" ~ private: int x;

" ~ public: void asig (int i) { x = i; }

" ~ void asig (void) { x = 0; }

" ~ };

"Tambi‚n hemos dicho que una funci¢n derivada puede tener miembros con los"

"mismos nombres que los miembros de la clase derivada. En este caso, utili-"

"zamos el operador :: para seleccionar el miembro. Por ejemplo:"

" ~class b ~ ~class d: public b

" ~ { ~ ~ {

" ~ private: int x; ~ ~ private: int x;

" ~ public: void asig (int i=0) {x=i;}~ ~ public: void asig (int i=0)

" ~ }; ~ ~ { x=i; b::asig (i); } };

"En los dos casos mencionados la funci¢n miembro seleccionada para ser"

"invocada es elegida en tiempo de compilaci¢n."

"En algunos casos interesa seleccionar din micamente (en tiempo de eje-"

"cuci¢n) la funci¢n miembro apropiada entre funciones de la clase base y"

"funciones de la clase derivada. La palabra clave ~virtual~ es un especi-"

"ficador de funci¢n que proporciona este mecanismo, pero s¢lo puede ser"

"usada para modificar declaraciones de funciones miembros."

"Una funci¢n virtual debe estar definida (no s¢lo declarada). Se invoca"

"igual que las dem s funciones. El prototipo de la funci¢n virtual en"

"la clase derivada debe ser igual que su prototipo en la clase base. Es"

"ilegal redinir una funci¢n virtual de tal manera que difiera s¢lo en el"

"tipo devuelto. Si dos funciones con el mismo nombre tienen diferentes"

"argumentos, C++ las considera diferentes, y el mecanimo de funci¢n vir-"

"tual es ignorado. El especificador virtual s¢lo es necesario ponerlo en"

"la declaraci¢n de la funci¢n de la clase base, no en la declaraci¢n de"

"la funci¢n en la clase derivada."

"Las funciones virtuales deben ser miembros de alguna clase, pero no"

"pueden ser miembros est ticos (static). Una funci¢n virtual puede ser"

"amiga (friend) de otra clase. Una £ltima restricci¢n: los constructores"

"no pueden ser virtuales, pero los destructores s¡ pueden serlo."

"// Primer ejemplo de funciones virtuales."

"#include <iostream.h>"

"class b"

{

" public:"

" virtual void vf1 (void) { cout << "b::vf1 "; }"

" virtual void vf2 (void) { cout << "b::vf2 "; }"

" virtual void vf3 (void) { cout << "b::vf3 "; }"

" void f (void) { cout << "b::f "; }"

};

"class d: public b"

{

" public:"

" virtual void vf1 (void) // especificador virtual es legal pero"

" { cout << "d::vf1 "; } // redundante"

" void vf2 (int) // no virtual, puesto que usa una lista de"

" { cout << "d::vf2 "; } // argumentos diferente"

" /*"

" char vf3 (void) { } // ilegal: s¢lo cambia el tipo devuelto"

" */"

" void f (void) { cout << "d::f "; } // no virtual"

};

"void main (void)"

{

" d cd; // declara un objeto d"

" b *pcb = &cd; // conversi¢n est ndar de d* a b*"

" pcb->vf1(); // llama a d::vf1()"

" pcb->vf2(); // llama a b::vf2() ya que d::vf2 tiene args. diferentes"

" pcb->vf3(); // llama a b::vf3()"

" pcb->f(); // llama a b::f() (no virtual)"

" pcb->b::vf1(); // llama a b::vf1()"

}

"/*"

" SALIDA DE ESTE PROGRAMA:"

" d::vf1 b::vf2 b::vf3 b::f b::vf1"

*/

"// Segundo ejemplo de funciones virtuales."

"#include <iostream.h>"

"class b"

{

" public:"

" int i;"

" b (void) { i = 1; }"

" virtual void imprimir_i (void) { cout << "\ni de clase b: " << i; }"

};

"class d1: public b"

{

" public:"

" d1 (void) { i = 2; }"

" void imprimir_i (void) { cout << "\ni de clase d1: " << i; }"

};

"class d2: public b"

{

" public:"

" int i;"

" d2 (void) { i = 3; }"

" void imprimir_i (void)"

" { cout << "\ni de clase d2: " << i << "; b::i de clase d2: " << b::i; }"

};

"void main (void)"

{

" b cb;"

" b *pcb = &cb;"

" d1 cd1;"

" d2 cd2;"

" pcb->imprimir_i (); // imprime: (r)i de clase b: 1¯"

" pcb = &cd1;"

" pcb->imprimir_i (); // imprime: (r)i de clase d1: 2¯"

" pcb = &cd2;"

" pcb->imprimir_i (); // imprime: (r)i de clase d2: 3; b::i de clase d2: 1¯"

}

FUNCIONES PURAS "

"En la secci¢n anterior hemos dicho que las funciones virtuales permiten"

"a las clases derivadas proporcionar diferentes versiones de una funci¢n"

"de la clase base; y tambi‚n hab¡amos dicho que las funciones virtuales"

"deben estar definidas en la clase base al igual que todas las funciones"

"miembros. Pues bien, hay una forma de no definir una funci¢n virtual en"

"la clase base: declar ndola pura."

"La forma de declarar una funci¢n pura es a¤adiendo ~= 0~ al final de la"

"declaraci¢n virtual. Ejemplo:"

" class b"

" {"

" virtual void vf (int) = 0; // = 0 significa pura"

" };"

"En una clase derivada de una clase base con funciones puras, cada funci¢n"

"pura debe ser definida o redeclarada como pura."

"Si una funci¢n virtual es definida en la base, no necesita ser redefinida"

"en las clases derivadas. Las llamadas simplemente llamar¡an a la funci¢n"

"de la clase base."

"// Ejemplo de funciones puras."

"#include <iostream.h>"

"class b"

{

" public:"

" void f1 (void) { cout << "\nb::f1()"; }"

" virtual void f2 (void) { cout << "\nb::f2()"; }"

" virtual void f3 (void) { cout << "\nb::f3()"; }"

" virtual void f4 (void) = 0;"

" /*"

" virtual void f5 (void) = 0; // ERROR: no definida en ninguna clase"

" // derivada"

" */"

};

"class d: public b"

{

" public:"

" void f1 (void) { cout << "\nd::f1()"; }"

" void f2 (int) { cout << "\nd::f2()"; }"

" void f3 (void) { cout << "\nd::f3()"; }"

" void f4 (void) { cout << "\nd::f4()"; }"

};

"void main (void)"

{

" d cd;"

" b *pcb = &cd;"

" pcb->f1(); // imprime: (r)b::f1()¯"

" pcb->f2(); // imprime: (r)b::f2()¯"

" pcb->f3(); // imprime: (r)d::f3()¯"

" pcb->f4(); // imprime: (r)d::f4()¯"

" /*"

" pcb->d::f1(); // error: d no es una clase base de b"

" */"

" pcb->b::f3(); // imprime: (r)b::f3()¯"

}

CLASES ABSTRACTAS "

Una clase abstracta es una clase que tiene al menos una funci¢n virtual

pura.

"Una clase abstracta s¢lo puede ser usada como una clase base para otras"

"clases."

"No se puede crear ning£n objeto de una clase abstracta."

"Una clase abstracta no puede ser usada como el tipo de un argumento ni como"

"el tipo devuelto por una funci¢n."

"Las referencias a una clase abstracta s¡ est n permitidas, esto permite que"

"no sea necesario un objeto temporal en la inicializaci¢n."

" *"

" ***"

" ***** "

" ***"

" *"

"// Ejemplo de clase abstracta."

"class ca // clase abstracta"

{

" private:"

" int x;"

" public:"

" void asigx (int i) { x = i; }"

" int devx (void) { return x; }"

" virtual void imprx (void) = 0; // funci¢n virtual pura"

};

"ca c; // ERROR: intento de crear un objeto de una clase abstracta"

"ca *p; // CORRECTO: puntero a una clase abstracta"

"ca f (void); // ERROR: el tipo devuelto no puede ser una clase abstracta"

"void g (ca); // ERROR: el tipo del argumento de una funci¢n no puede ser"

" // una clase abstracta"

"ca& h (ca&); // CORRECTO: el tipo del valor devuelto y el tipo del"

" // argumento de una funci¢n pueden ser una referencia"

" // a una clase abstracta"

"ca* l (ca*); // CORRECTO: el tipo del valor devuelto y el tipo del"

" // argumento de una funci¢n pueden ser un puntero a una"

" // clase abstracta"

Supongamos que d es una clase derivada con la clase abstracta b como

clase base inmediata. Entonces, para cada funci¢n virtual fv en b, la

clase d debe, o bien proporcionar una definici¢n para fv, o bien rede-

clarar fv como pura.

"// Ejemplo de definici¢n y redeclaraci¢n de funciones puras:"

"class b"

{

" public:"

" virtual void f (void) = 0;"

" virtual void g (void) = 0;"

" virtual void h (void) = 0;"

};

"class d: public b // clase d derivada de clase abstracta b"

{

" public:"

" void f (void) { } // funci¢n f definida: no realiza ninguna acci¢n"

" void g (void); // funci¢n g debe estar definida en alg£n sitio"

" void h (void); // funci¢n h redeclarada como pura"

};

"Las funciones miembros pueden ser llamadas desde un constructor"

"de una clase abstracta, pero llamar a una funci¢n virtual pura,"

"directa o indirectamente, desde tal constructor, provoca un error /"

"en tiempo de ejecuci¢n; lo cual, por otra parte, es l¢gico. /"

"/ / / / / / / /"

" / / / / / / /"

" / / / / / / /"

" / / / / / / / /"

" / / / / / / / /"

" / / / / / / /"

" / / / / / / /"

" / / / / / / / /"

" / / / / / / / /"

"/ / / / / / / /"

" / / / / / / /"

" / / / / / / /"

" / / / / / / / /"

"// Ejemplo de llamada a una funci¢n pura no definida (aunque s¡"

"// declarada)"

"class b"

{

" public:"

" int x;"

" b (int i = 0) { asig (i); }"

" virtual void asig (int i) = 0;"

};

"class d: public b"

{

" void asig (int i) { x = i; }"

};

"void main (void)"

{

" d cd;"

}

"/*"

" SALIDA DE ESTE PROGRAMA:"

" Pure virtual function called"

" NOTA:"

" El mensaje de error anterior puede variar entre distintas"

" implementaciones de C++; este programa ha sido compilado"

" con Borland C++ 2.0. Recalcar que el error se produce en"

" tiempo de ejecuci¢n, no en tiempo de compilaci¢n."

*/

" Las funciones virtuales pagan un precio por su versatilidad:"

" cada objeto en la clase derivada necesita llevar un puntero"

" a una tabla de funciones, necesario para seleccionar la fun-"

" ci¢n correcta en tiempo de ejecuci¢n."

" Por lo tanto, cuando no sea estrictamente necesario el uso"

" de funciones virtuales, es preferible utilizar el operador"

" de resoluci¢n de mbito"

" nombre_de_clase::nombre_de_funcion_miembro"

" para seleccionar la funci¢n miembro a invocar."

JERARQUIA DE CLASES "

"º~ Una clase derivada puede ser a su vez clase base de otra clase derivada. ~º"

"// Ejemplo de jerarqu¡a de clases."

"#include <iostream.h>"

"class c1 // clase base inmediata de c1 y no inmediata de c3"

" {"

" public:"

" int x;"

" c1 (int i = 0) { x = i; }"

};

"class c2: public c1 // clase derivada de c1 y base de c3"

{

" public:"

" int x;"

" c2 (int i = 0): c1 (2 * i) { x = i; }"

};

"class c3: public c2 // clase derivada inmediata de c2 y no inmediata de c1"

{

" public:"

" int x;"

" c3 (int i = 0): c2 (3 * i) { x = i; }"

};

"void main (void)"

{

" c3 c (4);"

" cout << c.c1::x << ' '; // imprime: 24"

" cout << c.c2::x << ' '; // imprime: 12"

" cout << c.c3::x << ' '; // imprime: 4"

" cout << c.x << ' '; // imprime: 4"

}

; LECCION 7

HERENCIA MULTIPLE "

" ~ ~ "

" ~ En la lecci¢n anterior estudiamos la ~herencia simple~ (una

" ~ clase derivada puede tener £nicamente una clase base). En

" ~ esta lecci¢n estudiaremos la ~herencia m£ltiple~ (una clase

" ~ derivada puede tener m s de una clase base).

" ~

INDICE DE ESTA LECCION "

" ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ "

" ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

" En esta lecci¢n se va a estudiar los siguientes puntos:"

" - Forma general de declarar una clase."

" - Jerarqu¡a circular."

" - Ambigedad en los miembros."

" - Herencia virtual: clases virtuales."

" - Orden de llamada a los constructores y los destructores."

" - Destructores virtuales."

" - Orden de ejecuci¢n de un programa en Turbo C++."

" - Algunos ejemplos curiosos."

FORMA GENERAL DE DECLARAR UNA CLASE "

Cuando una clase derivada tiene m s de una clase base se habla de herencia

m£ltiple.

"La forma general de declarar una clase derivada es:"

" <palabra_clave_de_clase> <nombre_de_clase>: <lista_de_clases_bases>"

{

" <lista_de_miembros>"

" }"

"donde:"

" - <palabra_clave_de_clase> es la palabra clave class, struct o union."

" - <nombre_de_clase> debe ser un nombre £nico dentro de su mbito."

" - <lista_de_clases_bases> es la lista de clases bases separadas por comas,"

" cada clase base en esta lista puede ir precedida por la palabra clave"

" public o private."

" - <lista_de_miembros> consiste en la declaraci¢n de los datos miembros y"

" las funciones miembros."

"// Ejemplo de herencia m£ltiple."

"#include <iostream.h>"

"class b1"

" {"

" public:"

" int x;"

" b1 (int i = 0) { x = i; }"

};

"class b2"

{

" public:"

" int x;"

" b2 (int i = 0) { x = i; }"

};

"class b3"

{

" public:"

" int x;"

" b3 (int i = 0) { x = i; }"

};

"class d: public b1, public b2, private b3"

{

" public:"

" int x;"

" d (int i = 0): b1 (2 * i), b2 (3 * i), b3 (-2 * i) { x = i; }"

};

"void main (void)"

{

" d cd (4);"

" cout << cd.b1::x << ' '; // imprime: 8"

" cout << cd.b2::x << ' '; // imprime: 12"

" cout << cd.d::x << ' '; // imprime: 4"

" cout << cd.x << ' '; // imprime: 4"

}

JERARQUIA CIRCULAR "

"La jerarqu¡a circular se da cuando una clase A es base de una clase B (no"

"necesariamente base inmediata) y la clase B es base de la clase A (no nece-"

"sariamente base inmediata). L¢gicamente, este tipo de jerarqu¡a es ilegal."

" ~ * * * * * * *

"Ejemplo: ~ * * * * * * *

" ~ * * * * * * *

" class x: z { /* ... */ }; ~ * * * * * * *

" class y: x { /* ... */ }; ~* * * * * * * *

" class z: y { /* ... */ }; ~ * * * * * *

" ~* * * * * * * * * *

"Estas declaraciones son incorrectas.~ * * * * *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

* * * *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

* * *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

* *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

*

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

AMBIGšEDAD EN LOS MIEMBROS "

"La ambigedad en los miembros se da cuando una clase deriva miembros con"

"id‚ntico nombre de diferentes clases y no hay ning£n miembro con ese nombre"

"en la clase derivada. Ilustremos esto con un ejemplo:"

" class x { public: int f (void); };"

" class y { public: int f (void); };"

" class z: public x, public y { public: void g (void) { x::f() + y::f(); } };"

" void main (void)"

" {"

" z clase;"

" clase.f (); // ERROR: ¨clase.x::f() o clase.y::f()?"

" }"

"Hay dos formas de solucionar este problema:"

" 1) Usando el operador de resoluci¢n de mbito :: para invocar a la funci¢n"

" f() que deseamos. De hecho, esto se ha hecho en g()."

" 2) A¤adir la funci¢n miembro f() a la clase derivada z. Por ejemplo:"

" class z: ... { ... void f (void) { ... } ... };"

HERENCIA VIRTUAL "

"Las clases virtuales se utilizan cuando una clase base se pasa m s de"

"una vez a una misma clase derivada, lo cual puede ocurrir en la herencia"

"m£ltiple."

"Una clase base no puede ser especificada m s de una vez en una clase"

"derivada:"

" ~class B { ...};

" ~class D : B, B { ... }; // Ilegal

"Sin embargo, una clase base se puede pasar indirectamente a una clase"

"derivada m s de una vez:"

" ~class X : public B { ... }

" ~class Y : public B { ... }

" ~class Z : public X, public Y { ... } // CORRECTO

"En este caso, cada objeto de clase Z tendr dos sub-objetos de clase B."

"Si esto causa probemas, se puede a¤adir la palabra clave virtual al"

"especificador de clase base. Por ejemplo,"

" ~class X : virtual public B { ... }

" ~class Y : virtual public B { ... }

" ~class Z : public X, public Y { ... }

"B es ahora una clase base virtual, y la clase Z tiene solamente un sub-"

"objeto de clase B."

ORDEN DE LLAMADAS A LOS CONSTRUCTORES Y LOS DESTRUCTORES "

"Los constructores de la clase base son llamados en el orden que fueron"

"declarados:"

" class Y { ... };"

" class X: public Y { ... };"

" X clase;"

"Orden de llamadas:"

" Y (); // constructor de clase base"

" X (); // constructor de clase derivada"

"Para el caso de clases bases m£ltiples:"

" class X: public Y, public Z { ... };"

" X clase;"

"los constructores son llamados en el orden de declaraci¢n:"

" Y (); // primero de la lista"

" Z ();"

" X ();"

"Los constructores para las clases bases vituales son invocados antes que"

"los de cualquier otra clase base no virtual."

"Si la jerarqu¡a contiene m£ltiples clases bases virtuales, los construc-"

"tores de las clases bases virtuales son invocados en el orden en el cual"

"fueron declarados. Los constructores de las clases bases no virtuales son"

"invocados antes que el constructor de la clase derivada."

"Si una clase virtual es derivada de una base no virtual, esa base no vir-"

"tual ser llamada primero, para que la clase base virtual sea construida"

"apropiadamente."

"Por ejemplo, el c¢digo"

" class X: public Y, virtual public Z { ... };"

" X clase;"

"produce el orden:"

" Z (); // inicializaci¢n de la clase base virtual"

" Y (); // clase base no virtual"

" X (); // clase derivada"

"En el caso que una jerarqu¡a de clases contiene m£ltiples instancias de"

"una clase base virtual, esa clase base es s¢lo construida una vez. Si,"

"sin embargo, existen las instacias virtual y no virtual de la clase base,"

"el constructor de la clase es invocado una sola vez para todas las ins-"

"tancias virtuales y una vez para cada ocurrencia no virtual de la clase"

"base."

"Un ejemplo m s complejo:"

" class base;"

" class base2;"

" class nivel1: public base2, virtual public base;"

" class nivel2: public base2, virtual public base;"

" class nivelalto: public nivel1, virtual public nivel2;"

" nivelalto clase;"

"El orden de los constructores es:"

" base(); // clase base virtual m s alta en la jerarqu¡a"

" // base es construida una s¢la vez"

" base2(); // base no virtual de nivel2 virtual"

" nivel2(); // clase base virtual"

" base2(); // base no virtual de nivel1"

" nivel1(); // base no virtual de nivel1"

" nivelalto(); // clase derivada"

"Antes se dijo que las clases bases son inicializadas en el orden de"

"declaraci¢n. Con los miembros ocurre lo mismo, son inicializados tambi‚n"

"en orden de declaraci¢n, independientemente de la lista de inicializaci¢n."

" class X"

{

" private:"

" int a, b;"

" public:"

" X (int i, int j): a (i), b (a + j) { }"

};

"Con esta clase, una declaraci¢n de X x (1, 1) resulta en un asignamiento"

"de 1 a x::a y de 2 a x::b."

" class base"

{

" private:"

" int x;"

" public:"

" base (int i): x (i) { }"

};

" class derivada: base"

{

" private:"

" int a;"

" public:"

" derivada (int i): a (i * 10), base (a) { } //­Ojo! Argumento pasado a"

" }; //base no est inicializado"

"Con esta clase, una llamada a d (1) no resultar en un valor de 10 para el"

"miembro x de la clase base. El valor pasado al constructor de la clase base"

"ser indefinido."

"Cuando se quiera una lista de inicializadores en un constructor no inline,"

"no colocar la lista en la declaraci¢n de la clase. En lugar de ello, ponerlo"

"en el punto en el cual la funci¢n es definida."

" derivada::derivada (int i): a (i)"

{

" ..."

" }"

"// Ejemplo sobre el orden de llamadas a los constructores y los destructores."

"// Ser¡a interesante para el usuario que intentara averiguar cu l es la"

"// salida antes de mirarla al final de esta ventana. Por ejemplo, observando"

"// el c¢digo fuente, podr¡a escribir la salida del programa en un papel, y"

"// una vez hecho esto, comprobarla con la salida real que est escrita al"

"// final de esta ventana."

"#include <iostream.h>"

"#include <conio.h>"

"#define declarar_clase(NOMBRE_CLASE) \"

" class NOMBRE_CLASE \"

" { \"

" public: \"

" NOMBRE_CLASE () { cout << "\nC "#NOMBRE_CLASE; } \"

" ~NOMBRE_CLASE () { cout << "\nD "#NOMBRE_CLASE; } \"

}

"declarar_clase (base1);"

"declarar_clase (base2);"

"declarar_clase (miembro1);"

"declarar_clase (miembro2);"

"class derivada1: public base2, public base1"

{

" public:"

" miembro1 m1_1, m1_2;"

" miembro2 m2;"

" derivada1 () { cout << "\nC derivada1"; }"

" ~derivada1 () { cout << "\nD derivada1"; }"

};

"class derivada2: public base1, virtual public base2"

{

" public:"

" derivada2 () { cout << "\nC derivada2"; }"

" ~derivada2 () { cout << "\nD derivada2"; }"

};

"class derivada3: virtual public derivada2, virtual public base2"

{

" public:"

" miembro1 m1;"

" derivada3 () { cout << "\nC derivada3"; }"

" ~derivada3 () { cout << "\nD derivada3"; }"

};

"class derivada4: virtual base2, derivada3"

{

" public:"

" miembro1 m1_1;"

" derivada3 d3;"

" miembro1 m1_2;"

" derivada4 () { cout << "\nC derivada4"; }"

" ~derivada4 () { cout << "\nD derivada4"; }"

};

"void main (void)"

{

{

" cout << "\n*** Declaraci¢n de una clase derivada1";"

" derivada1 d1;"

" }"

" getch ();"

{

" cout << "\n*** Declaraci¢n de una clase derivada2";"

" derivada2 d2;"

" }"

" getch ();"

{

" cout << "\n*** Declaraci¢n de una clase derivada3";"

" derivada3 d3;"

" }"

" getch ();"

{

" cout << "\n*** Declaraci¢n de una clase derivada4";"

" derivada4 d4;"

" }"

" getch ();"

}

"/*"

"SALIDA DEL PROGRAMA:"

"*** Declaraci¢n de una clase derivada1"

"C base2"

"C base1"

"C miembro1"

"C miembro1"

"C miembro2"

"C derivada1"

"D derivada1"

"D miembro2"

"D miembro1"

"D miembro1"

"D base1"

"D base2"

"*** Declaraci¢n de una clase derivada2"

"C base2"

"C base1"

"C derivada2"

"D derivada2"

"D base1"

"D base2"

"*** Declaraci¢n de una clase derivada3"

"C base2"

"C base1"

"C derivada2"

"C miembro1"

"C derivada3"

"D derivada3"

"D miembro1"

"D derivada2"

"D base1"

"D base2"

"*** Declaraci¢n de una clase derivada4"

"C base2"

"C base1"

"C derivada2"

"C miembro1"

"C derivada3"

"C miembro1"

"C base2"

"C base1"

"C derivada2"

"C miembro1"

"C derivada3"

"C miembro1"

"C derivada4"

"D derivada4"

"D miembro1"

"D derivada3"

"D miembro1"

"D derivada2"

"D base1"

"D base2"

"D miembro1"

"D derivada3"

"D miembro1"

"D derivada2"

"D base1"

"D base2"

*/

DESTRUCTORES VIRTUALES "

"Un destructor puede ser declarado como virtual. Esto permite a un puntero"

"que apunta al objeto de una clase base llamar al destructor correcto en el"

"caso de que el puntero haga referencia actualmente a un objeto de una clase"

"derivada. El destructor de una clase derivada de una clase con un destructor"

"virtual es asimismo virtual."

"Ejemplo:"

" class color"

" {"

" public:"

" virtual ~color (); // destructor virtual para color"

" };"

" class rojo: public color"

" {"

" public:"

" ~rojo (); // destructor para rojo es virtual tambi‚n"

" };"

" class rojointenso: public rojo"

" {"

" public:"

" ~rojointenso (); // destructor de rojointenso es tambi‚n virtual"

" };"

" color *paleta[3];"

" paleta[0] = new rojo;"

" paleta[1] = new rojointenso;"

" paleta[2] = new color;"

"Esto produce:"

" delete paleta[0]; // El destructor para rojo es llamado,"

" // seguido por el destructor para color."

" delete paleta[1]; // El destructor para rojointenso es llamado,"

" // seguido por ~~rojo y ~~color."

" delete paleta[2]; // El destructor para color es invocado."

"Sin embargo, en el caso que ning£n constructor fuera declarado virtual,"

"delete paleta[0], delete paleta[1], y delete paleta[2] s¢lo llamar¡an al"

"destructor para clase color. Esto destruir¡a incorrectamente los dos pri-"

"meros elementos, los cuales eran actualmente de tipo rojo y rojointenso."

"Los constructores no pueden ser virtuales."

ORDEN DE EJECUCION DE UN PROGRAMA EN TURBO C++ "

"El orden de ejecuci¢n del final de un programa en Turbo C++ (o Borland C++)"

"es el que sigue:"

"- Las funciones atexit son ejecutadas en el orden que fueron insertadas."

"- Las funciones #pragma exit son ejecutadas en el orden de sus c¢digos de"

" prioridad."

"- Los destructores para las variables globales son llamados."

"El orden de ejecuci¢n al comienzo de un programa en Turbo C++ (o Borland C++)"

"es justo el contrario que el orden de terminaci¢n, es decir, invirtiendo los"

"tres puntos anteriores."

"Cuando se llama a exit dentro de un programa, los destructores no son"

"llamados para las variables locales en el mbito actual. Las variables"

"globales son destruidas en su orden normal."

"Si se llama a abort en cualquier lugar de un programa, ning£n destructor"

"es llamado, ni incluso para las variables con un mbito global."

"La funci¢n atexit(), cuyo prototipo se encuentra en el fichero stdlib.h,"

"fue discutida en el tutor de C. Sin embargo, las directivas #pragma startup"

"y #pragma exit no se explicaron, por este motivo se estudian a continuaci¢n:"

" ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ"

" #pragma startup <nombre_de_funci¢n> [priordidad]"

" #pragma exit <nombre_de_funci¢n> [prioridad]

" ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß"

"La directiva #pragma startup permite al progrma especificar funciones que"

"deben ser ejecutadas al principio del programa (antes que se llame a la"

"funci¢n main)."

"La directiva #pragma exit permite al programa especificar funciones que"

"deben ser ejecutadas al final del programa (justo despu‚s de que el programa"

"termina con _exit)."

" <nombre_de_funcion>"

" ßßßßßßßßßßßßßßßßßßß"

"<nombre_funcion> debe ser una funci¢n previamente declarada que no toma"

"ning£n argumento y devuelve void."

"Debe estar declarada como"

" void func (void);"

"El nombre de la funci¢n debe ser definido (o declarado) antes de la l¡nea"

"en la que se encuentra el pragma."

" [prioridad]"

" ßßßßßßßßßßß"

"El par metro opcional prioridad es un entero en el rango de 64 a 255."

" 0 = prioridad m s alta"

" 100 = prioridad por defecto"

" ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

" ³ No usar las prioridades de 0 to 63. ³"

" ³ Ellas son usadas por las librer¡as de C. ³"

" ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"Las funciones con prioridades m s altas son las primeras que se llaman al"

"comienzo y las £ltimas que se llaman al final."

"// Ejemplo sobre el orden de ejecuci¢n de un programa"

"#include <stdlib.h>"

"#include <iostream.h>"

"#define definir_funcion(nombre_funcion) \"

" void nombre_funcion (void) { cout << "\nFunci¢n "#nombre_funcion"()."; }"

"definir_funcion (f1);"

"definir_funcion (f2);"

"definir_funcion (f3);"

"definir_funcion (f4);"

"definir_funcion (f5);"

"definir_funcion (f6);"

"#pragma startup f1 80"

"#pragma startup f2 70"

"#pragma exit f5 90"

"#pragma exit f6"

"#define declarar_clase(nombre_clase) \"

"class nombre_clase \"

"{ \"

" public: \"

" nombre_clase() { cout << "\nConstructor de clase "#nombre_clase"."; } \"

" ~nombre_clase() { cout << "\nDestructor de clase "#nombre_clase"."; } \"

}

"declarar_clase (x);"

"x x;"

"void main (void)"

{

" declarar_clase (y);"

" y y;"

" atexit (f3);"

" atexit (f4);"

}

"/*"

"SALIDA DEL PROGRAMA:"

"Constructor de clase x."

"Funci¢n f2()."

"Funci¢n f1()."

"Constructor de clase y."

"Destructor de clase y."

"Funci¢n f4()."

"Funci¢n f3()."

"Funci¢n f6()."

"Funci¢n f5()."

"Destructor de clase x."

*/

ALGUNOS EJEMPLOS CURIOSOS

// Misc‚lanea de ejemplos.

#ifdef __TCPLUSPLUS__ || __BCPLUSPLUS

# pragma warn -aus // evita aviso de valor asignado y nunca usado

# pragma warn -par // evita aviso de par metro no usado nunca

#endif

class x

{

private:

int i;

public:

x (void) { /* ... */ }

x (int x) { /* ... */ }

x (const x&) { /* ... */ }

};

void f1 (void)

{

x uno; // invoca constructor por defecto

x dos (1); // usa constructor x::x (int)

x tres = 1; // llama a x::x (int)

x cuatro = uno; // invoca a x::x (const x&) para la copia

x cinco (dos); // llama a x::x (const x&)

}

class base1

{

private:

int x;

public:

base1 (int i) { x = i; }

};

class base2

{

private:

int x;

public:

base2 (int i): x (i) { }

};

class derivada: public base1, public base2

{

private:

int a, b;

public:

derivada (int i, int j): base1 (i * 2), base2 (i + j), a (i) { b = j; }

};

void f2 (void)

{

derivada derivada (-2, 3); // inicializa base1 con -4 y base 2 con 1

}

class y

{

public:

int a, b;

public:

y (int i, int j): b (a + j), a (i) { } // a es inicializado antes que b

};

void f3 (void)

{

y y (1, 2); // a es inicializado con 1 y b es inicializado con 3

}

class z: virtual y

{

private:

virtual y cy;

public:

z (int i, int j): cy (a, b), y (j, i) {} // y() llamado antes que cy()

};

void f4 (void)

{

z z (1, 1); // a es inicializado con 1 y b es inicializado con 2

}

void main (void)

{

f1 ();

f2 ();

f3 ();

f4 ();

}

; LECCION 8

ENTRADA/SALIDA EN C++

~Esta lecci¢n describe la entrada y la salida en C++. La biblioteca de

~entrada/salida para el C, descrita por el fichero de cabecera stdio.h,

~est todav¡a disponible en C++. Sin embargo, es preferible utilizar las

~bibliotecas espec¡ficas para C++. En los primeros est ndares de C++, el

~conjunto de clases para los flujos de E/S estaba descrita en el fichero

~de cabecera stream.h. La utilizaci¢n de este fichero se considera hoy

~d¡a obsoleta. Para terminar la lecci¢n detallaremos dos ficheros de ca-

~becera (bcd.h y complex.h) que no tienen nada que ver con la E/S pero

~que se incluyen en esta lecci¢n por ser ‚sta la £nica en que se descri-

~ben los distintos ficheros de cabecera de C++.

INDICE DE ESTA LECCION

En esta lecci¢n se van a estudiar los siguientes puntos:

- Jerarqu¡a de clases de E/S.

- Ficheros de cabecera: iostream.h, fstream.h y strstream.h.

- Clases definidas en iostream.h: streambuf, ios, istream,

ostream, iostream, istream_withassign y ostream_withassign.

- Clases definidas en fstream.h: filebuf, fstreambase, ifstream,

ofstream y fstream.

- Clases definidas en strstream.h: strstreambuf, strstreambase,

istrstream, ostrstream y strstream.

- Clases bcd y complex.

ATENCION: Toda la informaci¢n proporcionada en esta lecci¢n pertenece

al Borland C++ 2.0. La presentaci¢n de los listados (resumidos) de los

ficheros de cabecera es necesario tomarlos de alg£n compilador. En es-

te caso se ha tomado de dicha versi¢n que es con la que se ha desarro-

llado todo el tutor. La inclusi¢n (resumida) de los ficheros de cabe-

cera se ha presentado en esta lecci¢n para facilitar al usurio la com-

prensi¢n de las clases declaradas en C++. Obviamente, el usuario no

tiene la necesidad de examinar tales listados aunque s¡ es muy reco-

mendable que lo haga para ver c¢mo est n implementadas las clases ex-

plicadas. Las dem s versiones de Borland C++ y de Turbo C++ as¡ como

de otros compiladores que no sean Borland International deber n tener

descripciones similares de las clases y ficheros de cabeceras comenta-

dos. Si se comprende la jerarqu¡a de clases de E/S explicada en esta

lecci¢n sobre el compilador citado de Borland, no se debe tener mucha

dificultad para comprender otra jerarqu¡a de clases de E/S de otros

compiladores.

JERARQUIA DE CLASES DE E/S

ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ

ÉÍÍÍ Clases de E/S en C++ ÉÍÍÍ

ºiosº ßßßßßßßßßßßßßßßßßßßß ºiosº

ÈÑÑÑÊÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÑÑÑ1/4

ÚÄÄÄÄÄÄÄÄÙ³ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ Ý ÚÄÄÄÄÄÄÄÙ³ÀÄÄÄÄÄÄÄÄÄÄ¿

ÉÍÍÍÏÍÍÍ ÉÍÍÍÏÍÍÍ ÉÍÍÍÍÍÍÏÍÍÍÍ Ý ÉÍÍÍÏÍÍÍÉÍÍÍÏÍÍÍÉÍÍÍÍÍÍÏÍÍÍÍÍÍ

ºistreamº ºostreamº ºfstreambaseº Ý ºistreamººostreamººstrstreambaseº

ÈÑÑÍÑÍÍÍ1/4 ÈÑÍÑÍÑÍÍ1/4 ÈÍÍÍÍÍÍÍÍÑÑÑ1/4 Ý ÈÑÍÑÍÍÍÍ1/4ÈÑÍÑÍÍÍÍ1/4ÈÍÍÍÍÑÑÑÍÍÍÍÍÍ1/4

³³ÉÏÍÍÍÍÍÍϳÉÏÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ ³³³ Ý ³ÉÏÍÍÍÍÍÍÏÀÄÄÄÄ¿ÚÄÄÄÄÙ³³

³³ºiostreamº³ºostream_withassignº ³³³ Ý ³ºiostreamºÉÍÍÍÍÏÏÍÍÍͳ³

³³ÈÑÍÍÍÍÍÍÑ1/4³ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ1/4 ³³³ Ý ³ÈÍÍÍÑÍÍÍÍ1/4ºostrstreamº³³

³³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ÚÄÄÄÄÙ³³ Ý ³ ³ ÈÍÍÍÍÍÍÍÍÍÍ1/4³³

³³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄ¿ÉÍÍÍÏÏÍÍÍ ³³ Ý ³ ÀÄÄÄÄÄÄÄÄÄÄ¿ÚÄÄÄÄÄÙ³

³³ÉÏÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͳºofstreamº ³³ Ý ³ ÉÍÍÍÍÏÏÍÍÍ ³

³³ºiostream_withassignº³ÈÍÍÍÍÍÍÍÍ1/4 ³³ Ý ³ ºstrstreamº ³

³³ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ1/4ÀÄÄÄÄÄ¿ÚÄÄÄÄÙ³ Ý ³ ÈÍÍÍÍÍÍÍÍÍ1/4 ³

³ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÉÍÍÍÏÏÍÍ ³ Ý ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ÚÄÄÄÄÄÄÙ

ÉÏÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ ³ ºfstreamº ³ Ý ÉÍÍÍÍÏÏÍÍÍÍ

ºistream_withassignº ³ ÈÍÍÍÍÍÍÍ1/4 ³ Ý ºistrstreamº

ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ1/4 ÀÄÄÄÄÄ¿ÚÄÄÄÄÄÙ Ý ÈÍÍÍÍÍÍÍÍÍÍ1/4

ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ ÉÍÍÍÏÏÍÍÍ Ý

ÉÍÍÍÍÍÍÍÍÍ Þ ºifstreamº Ý

ºstreambufº Þ ÈÍÍÍÍÍÍÍÍ1/4 Ý

ÈÍÑÍÍÍÍÍÑÍ1/4 Þ

ÉÍÍÍÍÍÏÍ ÉÍÏÍÍÍÍÍÍÍÍÍÍÞ

ºfilebufº ºstrstreambufºÞ

ÈÍÍÍÍÍÍÍ1/4 ÈÍÍÍÍÍÍÍÍÍÍÍÍ1/4Þ

FICHEROS DE

Hay tres ficheros de cabecera en la que est n declaradas las

clases anteriores:

ÍÍÍÍÍÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

~iostream.h~ ³ declara los flujos b sicos

³

~fstream.h~ ³ declara las clases de flujos de C++ que soportan

³ entrada y salida de ficheros

³

~strstream.h~ ³ declara las clases de flujos de C++ para usarlas

³ con arrays de bytes en memoria

ÍÍÍÍÍÍÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

CLASES DEFINIDAS EN IOSTREAM.H

Clases definidas en el fichero iostream.h, desde las m s primitivas hasta

las m s especializadas:

ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

~streambuf~ ³ Proporciona m‚todos para los buffers de memoria.

~ios~ ³ Manipula errores y variables de estado de los flujos.

~istream~ ³ Manipula conversiones de caracteres formateadas y no

³ formateadas de un streambuf

~ostream~ ³ Manipula conversiones de caracteres formateadas y no

³ formateadas de un streambuf

~iostream~ ³ Combina istream y ostream para manipular operaciones

³ bidireccionales en un solo flujo.

~istream_withassign~ ³ Proporciona constructores y operadores de asignaci¢n

³ para el flujo cin.

~ostream_withassign~ ³ Proporciona constructores y operadores de asignaci¢n

³ para cout, cerr y clog.

ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

C++ proporciona estos objetos de flujos predefinidos:

ÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

~cin~ ³ Entrada est ndar, normalmente el teclado, se corresponde con stdin

³ en C

~cout~ ³ Salida est ndar, normalmente el teclado, se corresponde con stdout

³ en C

~cerr~ ³ Salida de error est ndar, normalmente la pantalla, se corresponde

³ con stderr en C

~clog~ ³ Una versi¢n completamente buffereada de cerr (no tiene equivalente

³ en C)

ÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

Se pueden redireccionar los flujos cin, cout, cerr y clog.

CLASES DEFINIDAS EN FSTREAM.H

ÍÍÍÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

~filebuf~ ³ Especializa la clase streambuf para manipular ficheros.

~fstreambase~ ³ Proporciona operaciones comunes a los flujos de ficheros.

~ifstream~ ³ Proporciona operaciones de entrada sobre un filebuf.

~ofstream~ ³ Proporciona operaciones de salida sobre un filebuf.

~fstream~ ³ Proporciona operaciones simult neas de entrada y salida

³ sobre un filebuf.

ÍÍÍÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

CLASES DEFINIDAS EN STRSTREAM.H

ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

~strstreambuf~ ³ Especializa la clase streambuf para formatos en memoria.

~strstreambase~ ³ Especializa la clase ios para los flujos de string.

~istrstream~ ³ Proporciona operaciones de entrada sobre un strstreambuf.

~ostrstream~ ³ Proporciona operaciones de salida sobre un strstreambuf.

~strstream~ ³ Proporciona operaciones simult neas de entrada y salida

³ sobre un strstreambuf.

ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

Nota: en realidad, el fichero tiene el nombre de strstrea.h, ya que un

nombre de fichero no puede tener m s de 8 caracteres en el DOS.

CLASE ios

ÜÜÜÜÜ

ios Proporciona operaciones comunes a la entrada y la salida

ßßßßß

ÚÄÄÄÄÄÄÄÄÄ¿ ÛßßßßßÛ

³<ninguna>ÃÄÄÄÄÛ ios ÛÄÄÄ¿

ÀÄÄÄÄÄÄÄÄÄÙ ÛÜÜÜÜÜÛ ³

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

ÃÄÄÄ´ fstreambase ³

³ ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵

ÃÄÄÄ´ istream ³

³ ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵

ÃÄÄÄ´ ostream ³

³ ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵

ÀÄÄÄ´ strstreambase ³

ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

Declarada en: iostream.h

Las clases derivadas de ios especializan la E/S con operaciones de formato

de alto nivel.

Constructores

ßßßßßßßßßßßßß

Asocia un streambuf dado con el flujo:

ios (streambuf *);

Funciones miembros

ßßßßßßßßßßßßßßßßßß

bad clear eof fail fill flags

good precision rdbuf rdstate setf tie

unsetf width

Definici¢n

ßßßßßßßßßß

class ios

{

public:

// bits de estado de flujo

enum io_state

{

goodbit = 0x00, // si est a 1, todo est correcto

eofbit = 0x01, // 1 en fin de fichero

failbit = 0x02, // fall¢ la £ltima operaci¢n de E/S

badbit = 0x04, // se intent¢ una operaci¢n incorrecta

hardfail = 0x80 // error irrecuperable

};

// modo de operaci¢n del flujo

enum open_mode

{

in = 0x01, // abre para lectura

out = 0x02, // abre para escritura

ate = 0x04, // busca fin de fichero en la apertura original

app = 0x08, // modo a¤adir: todas las adiciones se hacen al

// final del fichero

trunc = 0x10, // trunca fichero si ya existe

nocreate = 0x20, // la apertura falla si el fichero no existe

noreplace= 0x40, // la apertura falla si el fichero ya existe

binary = 0x80 // fichero binario (no de texto)

};

// direcci¢n de b£squeda en flujo

enum seek_dir { beg=0, cur=1, end=2 };

// indicadores de formato

enum

{

skipws = 0x0001, // salta espacios en blanco en la entrada

left = 0x0002, // salida ajustada a la izquierda

right = 0x0004, // salida ajustada a la derecha

internal = 0x0008, // relleno despu‚s de signo o indicador de base

dec = 0x0010, // conversi¢n decimal

oct = 0x0020, // conversi¢n octal

hex = 0x0040, // conversi¢n hexadecimal

showbase = 0x0080, // usa indicador de base en la salida

showpoint = 0x0100, // fuerza coma decimal (salida flotante)

uppercase = 0x0200, // salida hexadecimal en may£sculas

showpos = 0x0400, // a¤ade '+' a los enteros positivos

scientific= 0x0800, // usa notaci¢n flotante 1.2345E2

fixed = 0x1000, // usa notaci¢n flotante 123.45

unitbuf = 0x2000, // vuelca todos los flujos despu‚s de la inserc.

stdio = 0x4000 // vuelca stdio y stderr despu‚s de la inserci¢n

};

// constantes para el segundo par metro de seft()

static const long basefield; // dec | oct | hex

static const long adjustfield; // left | right | internal

static const long floatfield; // scientific | fixed

// constructor, destructor

ios (streambuf *);

virtual ~ios ();

// para leer/poner/borrar indicadores de formato

long flags ();

long flags (long);

long setf (long _setbits, long _field);

long setf (long);

long unsetf (long);

// lee/pone anchura de campo

int width ();

int width (int);

// lee/pone car cter de relleno

char fill ();

char fill (char);

// lee/pone d¡gitos de precisi¢n flotante

int precision (int);

int precision ();

// lee/pone ostream atado a este flujo

ostream * tie (ostream *);

ostream * tie ();

// obtiene estado actual del flujo

int rdstate (); // devuelve el estado del flujo

int eof (); // distinto de cero en fin de fichero

int fail (); // distinto de cero si fall¢ una operaci¢n

int bad (); // distinto de cero si ocurri¢ un error

int good (); // distinto de cero si no hay ning£n bit de

// estado a 1

void clear (int = 0); // pone el estado del flujo

operator void * (); // cero si estado con fallo

int operator! (); // distinto de cero si estado con fallo

streambuf * rdbuf (); // obtiene el streambuf asignado

// ...

private:

// ...

// estas declaraciones previenen la copia autom tica de un ios

ios (ios&); // declarado pero no definido

void operator= (ios&); // declarado pero no definido

};

Descripci¢n de los m‚todos

ßßßßßßßßßßßßßßßßßßßßßßßßßß

ÜÜÜÜÜ

bad Funci¢n miembro

ßßßßß

ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ios ³ No cero si ocurri¢ un error ³

³ ³ int bad () ³

ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜ

clear Funci¢n miembro

ßßßßßßß

ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ios ³ Pone el estado del flujo al valor dado: ³

³ ³ void clear (int = 0) ³

ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜ

eof Funci¢n miembro

ßßßßß

ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ios ³ No cero en fin de fichero ³

³ ³ int eof () ³

ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜ

fail Funci¢n miembro

ßßßßßß

ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ios ³ No cero si fall¢ una operaci¢n ³

³ ³ int fail () ³

ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜ

fill Funci¢n miembro

ßßßßßß

ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ios ³ Devuelve el car cter actual de relleno: ³

³ ³ char fill () ³

³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ ³ Pone car cter de relleno; devuelve el que hay previamente: ³

³ ³ char fill (char) ³

ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜ

flags Funci¢n miembro

ßßßßßßß

ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ios ³ Devuelve los indicadores del formato actual: ³

³ ³ long flags () ³

³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ ³ Pone los indicadores de formato para que sean id‚nticos ³

³ ³ al long dado; devuelve los indicadores previos: ³

³ ³ long flags (long) ³

ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜ

good Funci¢n miembro

ßßßßßß

ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ios ³ No cero si no hay ning£n bit de estado a 1 (no aparecieron errores) ³

³ ³ int good () ³

ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜÜÜÜÜ

precision Funci¢n miembro

ßßßßßßßßßßß

ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ios ³ Pone la precisi¢n de coma flotante; devuelve la precisi¢n previa: ³

³ ³ int precision (int) ³

³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ ³ Devuelve la precisi¢n actual de coma flotante: ³

³ ³ int precision () ³

ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜ

rdbuf Funci¢n miembro

ßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ios ³ Devuelve un puntero al streambuf asignado a este flujo: ³

³ ³ streambuf* rdbuf () ³

ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ fstream ³ Devuelve el buffer usado: ³

³ fstreambase ³ filebuf* rdbuf () ³

³ ifstream ³ ³

³ ofstream ³ ³

ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜÜÜ

rdstate Funci¢n miembro

ßßßßßßßßß

ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ios ³ Devuelve el estado del flujo: ³

³ ³ int rdstate () ³

ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜ

setf Funci¢n miembro

ßßßßßß

ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ios ³ Pone a 1 los bits de _field correspondientes a los bits de ³

³ ³ _setbits: ³

³ ³ long setf (long _setbits, long _field) ³

³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ ³ Pone a 1 los indicadores correspondientes al long dado; ³

³ ³ devuelve los indicadores previos: ³

³ ³ long setf (long) ³

ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜ

tie Funci¢n miembro

ßßßßß

ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ios ³ Devuelve el flujo antado, o 0 si no hay ninguno: ³

³ ³ ostream* tie () ³

³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ ³ Ata otro flujo a ‚ste y devuelve el flujo atado ³

³ ³ anterior, si lo hay: ³

³ ³ ostream* tie (ostream*) ³

ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

Los flujos atados son aqu‚llos que son conectados de tal forma que cuando

uno es usado, el otro es afectado de la misma forma.

Por ejemplo, cin y cout est n atados; cuando se usa cin, se vuelca cout

primero.

Cuando un flujo de entrada tiene caracteres para ser consumidos, o si un

flujo de salida necesita m s caracteres, el flujo atado es volcado en

primer lugar autom ticamente.

Por defecto, cin, cerr y clog est n atados a cout.

ÜÜÜÜÜÜÜÜ

unsetf Funci¢n miembro

ßßßßßßßß

ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ios ³ Pone a 0 los bits correspondientes al long ³

³ ³ dado; devuelve el long previo: ³

³ ³ long unsetf (long) ³

ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜ

width Funci¢n miembro

ßßßßßßß

ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ios ³ Devuelve la anchura atual: ³

³ ³ int width () ³

³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ ³ Pone la anchura dada; devuelve la anchura previa: ³

³ ³ int width (int) ³

ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

Programa ejemplo

ßßßßßßßßßßßßßßßß

// Ejemplo de algunas funciones de la clase ios.

/*

Los ejemplos se realizar n sobre el flujo cout que est predefinido en

iostream.h. El objeto cout no es del tipo ios sino de un tipo derivado

de la clase ios y por este motivo puede hacer uso de los miembros p£blicos

y protegidos de la clase ios. Normalmente la clase ios se suele utilizar

como clase base de otras clases derivadas y no directamente, por este

motivo, vamos a probar las funciones de ios con el flujo cout.

*/

#include <iostream.h>

#include <conio.h>

inline void nl (void)

{

cout << '\n';

}

void main (void)

{

clrscr ();

cout << 1; // imprime (r)1¯

int anchura_ant = cout.width (5);

int ch_de_relleno_ant = cout.fill ('*');

cout << 2; // imprime (r)****2¯

cout.width (anchura_ant);

cout.fill (ch_de_relleno_ant);

cout << 3; // imprime (r)3¯

nl ();

// la funci¢n width() s¢lo afecta a la siguiente salida

const numhex = 0x0F;

long indicadores = cout.flags ();

cout.width (4);

cout.fill ('#');

cout << numhex << numhex; // imprime (r)##1515¯

cout.width (4);

cout.flags (ios::hex);

cout << numhex; // imprime (r)####f¯

cout.width (4);

cout.setf (ios::uppercase | ios::showbase);

cout << numhex; // imprime (r)#0XF¯

cout.width (4);

cout.setf (ios::left, ios::adjustfield);

cout.width (4);

cout << numhex; // imprime (r)0XF#¯

cout.unsetf (ios::uppercase);

cout.width (4);

cout << numhex; // imprime (r)0xf#¯

cout.flags (ios::dec | ios::showpos);

cout.width (4);

cout << numhex; // imprime (r)#+15¯

cout.flags (ios::left);

cout.width (4);

cout << numhex; // imprime (r)##15¯ con flags y (r)#+15¯ si se hubiese hecho

// hecho cout.setf (ios::left) en vez de cout.flags (ios::left)

// Esa es la diferencia principal entre flags() y setf()

cout.flags (indicadores);

cout << numhex; // imprime (r)15¯

nl ();

const float numfloat = 2.3456;

cout << numfloat; // imprime (r)2.3456¯

cout.precision (2);

cout << ' ' << numfloat; // imprime (r) 2.35¯

cout.setf (ios::scientific);

cout << ' ' << numfloat; // imprime (r) 2.35e+00¯

cout.setf (ios::fixed | ios::showpoint);

cout << ' ' << float (int (numfloat)); // imprime (r)2.00¯

nl ();

// la siguiente l¡nea imprime: <valor_no_cero> <valor_no_cero> 0

// donde <valor_no_cero> es un valor distinto de 0. En la sentencia

// cout << cout; se realiza la conversi¢n impl¡cita:

// cout << (void *) cout; Esto es pr ctico para utilizarlo en expresiones

// de condiciones como las del while: while (cout) ... Aunque con el cout

// puede no ser muy £til s¡ lo es con los objetos de tipo fstream que

// veremos m s adelante

cout << cout << ' ' << (void *) cout << ' ' << ! cout;

// los modos de operaci¢n de y los bits y funciones de estado de los

// flujos se probar n cuando se estudien las clases ifstream, ofstream

// y fstream, que son derivadas de la clase ios y por lo tanto utilizan

// todas estas caracter¡sticas de la clase base ios

getch ();

}

CLASE streambuf

ÜÜÜÜÜÜÜÜÜÜÜ

streambuf Clase para manipular buffers.

ßßßßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

ÚÄÄÄÄÄÄÄÄÄ¿ ÛßßßßßßßßßßßÛ ÚÄ´ filebuf ³

³<ninguna>ÃÄÄÄÛ streambuf ÛÄÄ´ ÆÍÍÍÍÍÍÍÍÍÍÍÍÍ͵

ÀÄÄÄÄÄÄÄÄÄÙ ÛÜÜÜÜÜÜÜÜÜÜÜÛ ÀÄ´ strstreambuf ³

ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

Declarada en: iostream.h

Normalmente, deber¡amos usar las clases derivadas en nuestras aplicaciones,

en vez de streambuf.

Constructores

ßßßßßßßßßßßßß

Crea un objeto buffer vac¡o:

streambuf ()

Usa el array y el tama¤o dados como el buffer:

streambuf (char *, int)

Funciones miembros

ßßßßßßßßßßßßßßßßßß

in_avail out_waiting sbumpc seekoff seekpos

sgetc sgetn setbuf snextc sputbackc

sputc sputn stossc

Definici¢n

ßßßßßßßßßß

class _CLASSTYPE streambuf

{

public:

// constructores and destructores

streambuf (); // hace un streambuf vac¡o

streambuf (char *, int); // hace un streambuf con un array de

// caracteres dado

virtual ~streambuf();

// usa el array de caracteres proporcionado para el buffer si es posible

virtual streambuf * setbuf (signed char *, int);

// AVISO: esta funci¢n no es virtual; no la vuelvas a definir igual

streambuf * setbuf (unsigned char *, int);

// obtener (extraer) caracteres

int sgetc (); // obtiene pr¢ximo car cter

int snextc (); // avanza y devuelve pr¢ximo car cter

int sbumpc (); // devuelve car cter actual y avanza

void stossc (); // avanza a pr¢ximo car cter

int sgetn (char *, int); // obtiene los pr¢ximos n caracteres

virtual int do_sgetn (char *, int); // implementaci¢n de sgetn

virtual int underflow (); // llena buffer vac¡o

int sputbackc (char); // devuelve car cter a la entrada

virtual int pbackfail (int); // implementaci¢n de sputbackc

int in_avail (); // n£mero de caracteres disponibles

// en buffer

// poner (insertar) caracteres

int sputc (int); // pone un car cter

int sputn (const char *, int); // pone n caracteres de string

virtual int do_sputn (const char * s, int n); // implementaci¢n de sputn

virtual int overflow (int = EOF); // vuelca buffer y hace m s sitio

int out_waiting (); // n£mero de caracteres no volcados

// mueve puntero en flujo

virtual streampos seekoff (streamoff, seek_dir,

int = (ios::in | ios::out));

virtual streampos seekpos (streampos, int = (ios::in | ios::out));

virtual int sync ();

// ...

};

Descripci¢n de los m‚todos

ßßßßßßßßßßßßßßßßßßßßßßßßßß

ÜÜÜÜÜÜÜÜÜÜ

in_avail Funci¢n miembro

ßßßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ streambuf ³ Devuelve el n£mero de caracteres restantes en el ³

³ ³ buffer de entrada: ³

³ ³ int in_avail () ³

ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜÜÜÜÜÜÜ

out_waiting Funci¢n miembro

ßßßßßßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ streambuf ³ Devuelve el n£mero de caracteres restantes en el ³

³ ³ buffer de salida: ³

³ ³ int out_waiting () ³

ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜÜ

sbumpc Funci¢n miembro

ßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ streambuf ³ Devuelve el car cter actual del buffer de entrada, ³

³ ³ entonces avanza: ³

³ ³ int sbumpc () ³

ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜÜÜ

seekoff Funci¢n miembro

ßßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ filebuf ³ Mueve el puntero de fichero relativo a la posici¢n actual: ³

³ ³ virtual long seekoff (long, seek_dir, int) ³

ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ streambuf ³ Mueve el puntero de lectura y/o escritura (el tercer ³

³ ³ argumento determina cu l de los dos o ambos) relativo ³

³ ³ a la posici¢n actual: ³

³ ³ virtual long seekoff (long, seek_dir, ³

³ ³ int = (ios::in | ios::out)) ³

ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ strstreambuf ³ Mueve el puntero relativo a la posici¢n actual: ³

³ ³ virtual long seekoff(long, seek_dir, int) ³

ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜÜÜ

seekpos Funci¢n miembro

ßßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ streambuf ³ Mueve el puntero de lectura y/o escritura a una posici¢n ³

³ ³ absoluta: ³

³ ³ virtual long seekpos(long, int = (ios::in | ios::out)) ³

ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜ

sgetc Funci¢n miembro

ßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ streambuf ³ Devuelve el pr¢ximo car cter en el buffer de entrada: ³

³ ³ int sgetc10 () ³

ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜ

sgetn Funci¢n miembro

ßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ streambuf ³ Obtiene los pr¢ximos n caracteres del buffer de entrada: ³

³ ³ int sgetn (char*, int n) ³

ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜÜ

setbuf Funci¢n miembro

ßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ filebuf ³ Especifica el buffer a usar: ³

³ strstreambuf ³ virtual streambuf* setbuf (char*, int) ³

ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ fstreambase ³ Usa un buffer especificado: ³

³ ³ void setbuf (char*, int) ³

ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ streambuf ³ Conecta a un buffer dado: ³

³ ³ virtual streambuf* setbuf (signed char*, int) ³

ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜÜ

snextc Funci¢n miembro

ßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ streambuf ³ Avanza a (y devuelve el pr¢ximo car cter de) el ³

³ ³ buffer de entrada: ³

³ ³ int snextc () ³

ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜÜÜÜÜ

sputbackc Funci¢n miembro

ßßßßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ streambuf ³ Devuelve un car cter a la entrada: ³

³ ³ int sputbackc (char) ³

ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜ

sputc Funci¢n miembro

ßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ streambuf ³ Put one character into the output buffer: ³

³ ³ int sputc(int) ³

ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜ

sputn Funci¢n miembro

ßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ streambuf ³ Pone n caracteres en el buffer de salida: ³

³ ³ int sputn (const char*, int n) ³

ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜÜ

stossc Funci¢n miembro

ßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ streambuf ³ Avanza al pr¢ximo car cter en el buffer de entrada: ³

³ ³ void stossc () ³

ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

Programa ejemplo

ßßßßßßßßßßßßßßßß

// Este ejemplo prueba algunos m‚todos (funciones miembros) de la clase

// streambuf.

/*

Los ejemplos se realizar n accediendo al streambuf de los flujos cout y

cin a trav‚s de la funci¢n miembro rdbuf() de la clase ios. Los objetos

cout y cin no son del tipo ios sino de un tipo derivado de la clase ios

y por este motivo pueden hacer uso de los miembros p£blicos y protegidos

de la clase ios.

*/

#include <iostream.h>

#define nl << \n

void main (void)

{

cout << char ((cin.rdbuf())->sputbackc ('X')) nl; // imprime (r)X¯

cout << (cin.rdbuf())->in_avail () nl; // imprime (r)1¯

cout << char ((cin.rdbuf())->sgetc()) nl; // imprime (r)X¯

cout << char ((cout.rdbuf())->sputbackc ('X')) nl; // imprime (r)X¯

cout << (cout.rdbuf())->out_waiting () nl; // imprime (r)0¯

cout << char ((cout.rdbuf())->sputc('X')) nl; // imprime (r)XX¯

}

CLASE istream

ÜÜÜÜÜÜÜÜÜ

istream Proporciona entrada formateada y no formateada de un streambuf

ßßßßßßßßß

ÚÄÄÄÄÄ¿ ÛßßßßßßßßßÛ

³ ios ÃÄÄÄÛ istream ÛÄÄÄ¿

ÀÄÄÄÄÄÙ ÛÜÜÜÜÜÜÜÜÜÛ ³

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

ÃÄÄÄ´ ifstream ³

³ ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵

ÃÄÄÄ´ iostream ³

³ ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵

ÃÄÄÄ´ istream_withassign ³

³ ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵

ÀÄÄÄ´ istrstream ³

ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

Declarada en: iostream.h

Constructores

ßßßßßßßßßßßßß

Asocia un streambuf dado con el flujo:

istream (streambuf *)

Funciones miembros

ßßßßßßßßßßßßßßßßßß

gcount get getline ignore peek putback read

seekg tellg

Definici¢n

ßßßßßßßßßß

class istream : virtual public ios

{

public:

// constructor y destructor

istream (streambuf *);

virtual ~istream ();

// ...

// pone/lee la posici¢n del puntero de lectura

istream& seekg (streampos);

istream& seekg (streamoff, seek_dir);

streampos tellg ();

int sync ();

/*

* Operaciones de extracci¢n no formateadas

*/

// extrae caracteres coloc ndolos en un array

istream& get (signed char *, int, char = '\n');

istream& get (unsigned char *, int, char = '\n');

istream& read (signed char *, int);

istream& read (unsigned char *, int);

// extrae caracteres coloc ndolos en un array hasta encontrar el

// car cter de terminaci¢n dado como m ximo

istream& getline (signed char *, int, char = '\n');

istream& getline (unsigned char *, int, char = '\n');

// extrae caracteres coloc ndolos en un streambuf hasta encontrar el

// car cter de terminaci¢n dado como m ximo

istream& get (streambuf&, char = '\n');

// extrae un solo car cter

istream& get (unsigned char&);

istream& get (signed char&);

int get ();

int peek (); // devuelve pr¢ximo car cter sin extracci¢n

int gcount (); // n£mero de caracteres no formateados en la

// £ltima extracci¢n

istream& putback (char); // devuelve un car cter a la entrada

// extrae y desecha caracteres pero para al encontrar el delimitador

istream& ignore (int = 1, int = EOF);

/*

* Operaciones de extracci¢n formateadas

*/

istream& operator>> (istream& (*_f) (istream&));

istream& operator>> (ios& (*_f) (ios&));

istream& operator>> (signed char *);

istream& operator>> (unsigned char *);

istream& operator>> (unsigned char&);

istream& operator>> (signed char&);

istream& operator>> (short&);

istream& operator>> (int&);

istream& operator>> (long&);

istream& operator>> (unsigned short&);

istream& operator>> (unsigned int&);

istream& operator>> (unsigned long&);

istream& operator>> (float&);

istream& operator>> (double&);

istream& operator>> (long double&);

// extrae de este istream, insertando en streambuf

istream& operator>> (streambuf *);

protected:

istream ();

void eatwhite (); // extrae espacios blancos consecutivos

private:

// ...

};

Descripci¢n de los m‚todos

ßßßßßßßßßßßßßßßßßßßßßßßßßß

ÜÜÜÜÜÜÜÜ

gcount Funci¢n miembro

ßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ istream ³ Devuelve el n£mero de caracteres extra¡dos en la ³

³ ³ £ltima operaci¢n: ³

³ ³ int gcount () ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜ

get Funci¢n miembro

ßßßßß

ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ istream ³ Extrae el pr¢ximo car cter o EOF: ³

³ ³ int get () ³

³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ ³ Extra caracteres coloc ndolos en el char * dado hasta que el ³

³ ³ delimitador (tercer par metro) o el fin-de-fichero es encon- ³

³ ³ trado, o hasta que (len - 1) bytes han sido le¡dos: ³

³ ³ istream& get (signed char*, int len, char = '\n') ³

³ ³ istream& get (unsigned char*, int len, char = '\n') ³

³ ³ ³

³ ³ þ Un nulo de terminaci¢n es siempre colocado en el string ³

³ ³ de salida; el delimitador nunca es colocado. ³

³ ³ þ Falla s¢lamente si no es extra¡do ning£n car cter. ³

³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ ³ Extra un solo car cter coloc ndolo en la referencia a ³

³ ³ car cter dada: ³

³ ³ istream& get (unsigned char&) ³

³ ³ istream& get (signed char&) ³

³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ ³ Extrae caracteres coloc ndolos en el streambuf dado hasta que ³

³ ³ se encuentra el delimitador: ³

³ ³ istream& get (streambuf&, char = '\n') ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜÜÜ

getline Funci¢n miembro

ßßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ istream ³ Igual que get, excepto que tambi‚n se extrae el delimitador: ³

³ ³ istream& getline (signed char*, int, char = '\n') ³

³ ³ istream& getline (unsigned char*, int, char = '\n') ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜÜ

ignore Funci¢n miembro

ßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ istream ³ Salta un m ximo de n caracteres en el flujo de entrada; ³

³ ³ para cuando encuentra el delimitador: ³

³ ³ istream& ignore (int n = 1, int delim = EOF) ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜ

peek Funci¢n miembro

ßßßßßß

ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ istream ³ Devuelve pr¢ximo car cter sin extracci¢n: ³

³ ³ int peek () ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜÜÜ

putback Funci¢n miembro

ßßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ istream ³ Devuelve un car cter al flujo: ³

³ ³ istream& putback (char) ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜ

read Funci¢n miembro

ßßßßßß

ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ istream ³ Extrae un n£mero dado de caracteres coloc ndolos en un array: ³

³ ³ istream& read (signed char*, int) ³

³ ³ istream& read (unsigned char*, int) ³

³ ³ ³

³ ³ Usa gcount() para determinar el n£mero de caracteres le¡dos ³

³ ³ realmente si ocurre un error. ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜ

seekg Funci¢n miembro

ßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ istream ³ Mueve a una posici¢n absoluta (normalmente el argumento ³

³ ³ es el valor devuelto por tellg): ³

³ ³ istream& seekg (long) ³

³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ ³ Mueve a una posici¢n relativa a la posici¢n actual: ³

³ ³ istream& seekg (long, seek_dir) ³

³ ³ ³

³ ³ Usa esta definici¢n para seek_dir: ³

³ ³ enum seek_dir { beg, cur, end }; ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜ

tellg Funci¢n miembro

ßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ istream ³ Devuelve la posici¢n actual del flujo: ³

³ ³ long tellg () ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

Programa ejemplo

ßßßßßßßßßßßßßßßß

// Este ejemplo prueba todos los m‚todos (funciones miembros) de la clase

// istream.

/*

Los ejemplos se realizar n sobre el flujo cin que est predefinido en

iostream.h. El objeto cin no es del tipo istream sino de un tipo derivado

de la clase istream y por este motivo puede hacer uso de los miembros

p£blicos y protegidos de la clase istream.

*/

#include <iostream.h>

#include <conio.h>

void main (void)

{

const tam = 100;

char cad1[tam], cad2[tam];

cout << "Introduce dos l¡neas:\n";

cin.getline (cad1, tam).getline (cad2, tam);

cout << "Primera l¡nea: " << cad1 << "\nSegunda l¡nea: " << cad2;

cout << "\n\nIntroduce una serie de caracteres terminados con * que

"ser n ignorados: ";

cin.ignore (tam, '*');

cout << "\nIntroduce 5 caracteres: ";

cin.read (cad1, 5);

cout << "Cadena le¡da: " << (cad1[cin.gcount()] = 0, cad1);

cout << "\nIntroduce un car cter:\n";

cout << "Car cter le¡do sin extracci¢n: " << char (cin.peek ());

cout << "\nCar cter le¡do con extracci¢n, devuelto y le¡do de nuevo:

<< char (cin.putback(cin.get()).get());

cout << "\n\nPosici¢n actual en flujo cin le¡da, puesta y le¡da de nuevo:

<< cin.seekg (cin.tellg ()).tellg ();

cout << "\n\nPulsa una tecla para finalizar.";

getch ();

}

/*

SALIDA:

(r)

Introduce dos l¡neas:

abc

d e f

Primera l¡nea: abc

Segunda l¡nea: d e f

Introduce una serie de caracteres terminados con * que ser n ignorados: as

df

g

h j*

Introduce 5 caracteres: qwert

Cadena le¡da:

qwer

Introduce un car cter:

Car cter le¡do sin extracci¢n: t

Car cter le¡do con extracci¢n, devuelto y le¡do de nuevo: t

Posici¢n actual en flujo cin le¡da, puesta y le¡da de nuevo: 11974

Pulsa una tecla para finalizar.

¯

OBSERVACIONES SOBRE LA SALIDA DEL PROGRAMA:

1) Observando el programa nos damos cuenta de que parte de la salida

mostrada corresponde a caracteres introducidos por teclado y visualizados

en la pantalla.

2) En la funci¢n read, al leer 5 caracteres, lee primero el car cter nueva

l¡nea que se encuentra en el buffer pues se puls¢ la tecla ENTER despu‚s

del *.

3) La funci¢n read no lee el car cter t pues le hemos dicho que lea

solamente 5 caracteres. Por lo tanto, el car cter t queda en el buffer

de entrada y la funci¢n get, que sigue a la read, lee el car cter que

se encuentra en el buffer en vez de pedir un car cter por teclado.

4) El n£mero 11974 es distinto en cada ejecuci¢n del programa. Las funciones

seekg() y tellg() son realmente £tiles al leer ficheros de discos.

*/

CLASE ostream

ÜÜÜÜÜÜÜÜÜ

ostream Proporciona salida formateada y no formateada a un streambuf.

ßßßßßßßßß

ÚÄÄÄÄÄ¿ ÛßßßßßßßßßÛ

³ ios ÃÄÄÄÛ ostream ÛÄÄÄ¿

ÀÄÄÄÄÄÙ ÛÜÜÜÜÜÜÜÜÜÛ ³

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

ÃÄÄÄ´ iostream ³

³ ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵

ÃÄÄÄ´ ofstream ³

³ ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵

ÃÄÄÄ´ ostream_withassign ³

³ ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵

ÀÄÄÄ´ ostrstream ³

ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

Declarada en: iostream.h

Constructores

ßßßßßßßßßßßßß

Asocia un streambuf dado con el flujo:

ostream (streambuf *)

Funciones miembros

ßßßßßßßßßßßßßßßßßß

flush seekp put tellp write

Definici¢n

ßßßßßßßßßß

class ostream : virtual public ios

{

public:

// constructores y destructores

ostream (streambuf *);

virtual ~ostream ();

// ...

ostream& flush ();

// pone/lee la posici¢n del puntero de escritura

ostream& seekp (streampos);

ostream& seekp (streamoff, seek_dir);

streampos tellp ();

/*

* Operaciones de inserci¢n no formateadas

*/

ostream& put (char); // inserta el car cter

ostream& write (const signed char *, int); // inserta el string

ostream& write (const unsigned char *, int); // inserta el string

/*

* Operaciones de inserci¢n formateadas

*/

// inserta el car cter

ostream& operator<< (signed char);

ostream& operator<< (unsigned char);

// para lo siguiente, inserta representaci¢n del valor n£merico

ostream& operator<< (short);

ostream& operator<< (unsigned short);

ostream& operator<< (int);

ostream& operator<< (unsigned int);

ostream& operator<< (long);

ostream& operator<< (unsigned long);

ostream& operator<< (float);

ostream& operator<< (double);

ostream& operator<< (long double);

// inserta string terminado en nulo

ostream& operator<< (const signed char *);

ostream& operator<< (const unsigned char *);

// inserta representaci¢n del valor del puntero

ostream& operator<< (void *);

// extrae de streambuf, insertando en este otream

ostream& operator<< (streambuf *);

// manipuladores

ostream& operator<< (ostream& (*_f) (ostream&));

ostream& operator<< (ios& (*_f) (ios&));

protected:

// ...

private:

// ...

};

Descripci¢n de los m‚todos

ßßßßßßßßßßßßßßßßßßßßßßßßßß

ÜÜÜÜÜÜÜ

flush Funci¢n miembro

ßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ostream ³ Vuelca el flujo: ³

³ ³ ostream& flush () ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜ

seekp Funci¢n miembro

ßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ostream ³ Mueve a una posici¢n absoluta (normalmente el argumento ³

³ ³ es un valor devuelto por tellp): ³

³ ³ ostream& seekp (long) ³

³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ ³ Mueve a una posici¢n relativa a la posici¢n actual: ³

³ ³ ostream& seekp (long, seek_dir) ³

³ ³ ³

³ ³ Usa esta definici¢n para seek_dir: ³

³ ³ enum seek_dir { beg, cur, end }; ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜ

put Funci¢n miembro

ßßßßß

ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ostream ³ Inserta el car cter: ³

³ ³ ostream& put (char) ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜ

tellp Funci¢n miembro

ßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ostream ³ Devuelve la posici¢n actual del flujo: ³

³ ³ long tellp () ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÜÜÜÜÜÜÜ

write Funci¢n miembro

ßßßßßßß

ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³ ostream ³ Inserta n caracteres (incluido nulos): ³

³ ³ ostream& write (const signed char*, int n) ³

³ ³ ostream& write (const unsigned char*, int n) ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

Programa ejemplo

ßßßßßßßßßßßßßßßß

// Este ejemplo prueba todos los m‚todos (funciones miembros) de la clase

// ostream.

/*

Los ejemplos se realizar n sobre el flujo cout que est predefinido en

iostream.h. El objeto cout no es del tipo ostream sino de un tipo derivado

de la clase ostream y por este motivo puede hacer uso de los miembros

p£blicos y protegidos de la clase ostream.

*/

#include <iostream.h>

#include <conio.h>

#include <string.h>

void main (void)

{

cout.flush () << "Volcando flujo.";

cout << "\nPosici¢n actual en flujo cout le¡da, puesta y le¡da de nuevo:

<< cout.seekp (cout.tellp ()).tellp ();

const char *p = "\nInsertando esta cadena y el car cter X.";

const char lp = strlen (p);

cout.write (p, lp - 1).put (p[lp - 1]) << "\n";

getch ();

}

/*

SALIDA:

(r)

Volcando flujo.

Posici¢n actual en flujo cout le¡da, puesta y le¡da de nuevo: 2090

Insertando esta cadena y el car cter X.

¯

OBSERVACIONES SOBRE LA SALIDA DEL PROGRAMA:

1) El n£mero 2090 es distinto en cada ejecuci¢n del programa. Las

funciones seekp() y tellp() son realmente £tiles al leer ficheros

de discos.

*/

CLASE iostream

ÜÜÜÜÜÜÜÜÜÜ

iostream Permite entrada y salida sobre un flujo.

ßßßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄ¿

³ istream ÃÄ¿ ÛßßßßßßßßßßÛ ÚÄ´ fstream ³

ÆÍÍÍÍÍÍÍÍ͵ ÃÄÄÛ iostream ÛÄÄ´ ÆÍÍÍÍÍÍÍÍÍÍ͵

³ ostream ÃÄÙ ÛÜÜÜÜÜÜÜÜÜÜÛ ÀÄ´ strstream ³

ÀÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÙ

Declarada en: iostream.h

La clase iostream es simplemente una mezcla de sus clases bases, permitiendo

entrada y salida sobre un flujo.

Constructores

ßßßßßßßßßßßßß

Asocia un streambuf dado con el flujo:

iostream (streambuf *)

Funciones miembros

ßßßßßßßßßßßßßßßßßß

Ninguna

Definici¢n

ßßßßßßßßßß

class iostream : public istream, public ostream

{

public:

iostream (streambuf *);

virtual ~iostream ();

protected:

iostream ();

};

Programa ejemplo

ßßßßßßßßßßßßßßßß

// Este ejemplo prueba algunos m‚todos (funciones miembros) de la clase

// iostream.

/*

Los ejemplos se realizar n accediendo al streambuf de los flujos cout y

cin a trav‚s de la funci¢n miembro rdbuf() de la clase ios. Esta funci¢n

devuelve streambuf * y uno de los constructores de la clase iostream es

precisamente de ese tipo. El objeto cout no es del tipo ios sino de un

tipo derivado de la clase ios y por este motivo puede hacer uso de los

miembros p£blicos y protegidos de la clase ios.

*/

#include <iostream.h>

void main (void)

{

int x;

iostream ((iostream ((iostream (cout.rdbuf ()) << "Introduce x: ")

.rdbuf ()) >> x).rdbuf ()) << "x es ";

iostream ((iostream (cout.rdbuf ()) << x).rdbuf ()).flush ();

}

/*

SALIDA:

(r)

Introduce x: 5

x es 5

¯

OBSERVACIONES SOBRE LA SALIDA DEL PROGRAMA:

1) El primer 5 de la salida mostrada es el n£mero tecleado desde teclado

y visualizado en pantalla.

2) Los pasos que se realizan en la sentencia

iostream ((iostream ((iostream (cout.rdbuf ()) << "Introduce x: ")

.rdbuf ()) >> x).rdbuf ()) << "x es ";

son lo siguientes:

Paso Expresi¢n Tipo de la expr

---- -------------------------------------------------------- ---------------

1) cout.rdbuf () streambuf *

2) iostream (cout.rdbuf ()) iostream

3) iostream (cout.rdbuf ()) << "Introduce x: " ostream

4) (iostream (cout.rdbuf ()) << "Introduce x: ").rdbuf () streambuf *

5) iostream ((iostream (cout.rdbuf ()) << "Introduce x: ")

.rdbuf ()) iostream

6) iostream ((iostream (cout.rdbuf ()) << "Introduce x: ")

.rdbuf ()) >> x istream

6) (iostream ((iostream (cout.rdbuf ()) << "Introduce x: ")

.rdbuf ()) >> x).rdbuf () streambuf *

7) iostream ((iostream ((iostream (cout.rdbuf ())

<< "Introduce x: ").rdbuf ()) >> x).rdbuf ()) iostream

8) iostream ((iostream ((iostream (cout.rdbuf ())

<< "Introduce x: ").rdbuf ()) >> x).rdbuf ())

<< "x es " ostream

*/

CLASE istream_withassign

ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ

istream_withassign istream con un operador de asignaci¢n a¤adido

ßßßßßßßßßßßßßßßßßßßß

ÚÄÄÄÄÄÄÄÄÄ¿ ÛßßßßßßßßßßßßßßßßßßßßÛ ÚÄÄÄÄÄÄÄÄÄÄÄ¿

³ istream ÃÄÄÄÄÛ istream_withassign ÛÄÄÄÄ´ <ninguna> ³

ÀÄÄÄÄÄÄÄÄÄÙ ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ ÀÄÄÄÄÄÄÄÄÄÄÄÙ

Declarada en: iostream.h

Constructores

ßßßßßßßßßßßßß

Constructor nulo (llama a constructor de istream):

istream_withassign ()

Funciones miembros

ßßßßßßßßßßßßßßßßßß

Ninguna (Aunque el operador = est sobrecargado)

Definici¢n

ßßßßßßßßßß

class istream_withassign : public istream

{

public:

// no inicializaci¢n

istream_withassign ();

virtual ~istream_withassign ();

// obtiene buffer de ostream y hace inicializaci¢n completa

istream_withassign& operator= (istream&);

// asocia streambuf con flujo y hace inicializaci¢n completa

istream_withassign& operator= (streambuf *);

};

Programa ejemplo

ßßßßßßßßßßßßßßßß

// Este ejemplo prueba la clase istream_withassign

/*

El flujo cin es de tipo istream_withassign.

*/

#include <iostream.h>

void main (void)

{

const int longs = 256;

char s[longs];

cout << "\nIntroduce cadena: ";

cin >> s;

cout << "\nCadena introducida: " << s;

cout << "\nIntroduce l¡nea: ";

cin.getline (s, longs);

cout << "\nL¡nea introducida: " << s;

cout << "\nIntroduce cadena saltando espacios blancos: ";

cin.setf (ios::skipws);

cin >> s;

cout << "\nCadena introducida: " << s;

while ((cin.rdbuf())->in_avail ()) // desecha caracteres que hay en buffer

cin.get (); // para que pr¢ximo cin lea de teclado

cout << "\nIntroduce cadena sin saltar espacios blancos: ";"

" cin.unsetf (ios::skipws);"

" cin >> s;"

" cout << "\nCadena introducida: " << s;"

}

"/*"

"SALIDA:"

"(r)"

"Introduce cadena: Antonio Lebr¢n Bocanegra"

"Cadena introducida: Antonio"

"Introduce l¡nea"

"L¡nea introducida: Lebr¢n Bocanegra"

"Introduce cadena saltando espacios blancos: x"

"Cadena introducida: x"

"Introduce cadena sin saltar espacios blancos: x"

"Cadena introducida:"

"¯"

"OBSERVACIONES SOBRE LA SALIDA DEL PROGRAMA:"

"1) Parte del texto mostrado en la salida anterior corresponde a texto"

"introducido por teclado y visualizado en pantalla. Esto se ve claramente"

"observando el c¢digo fuente. Por supuesto, tanto la salida como la"

"entrada se pueden redirigir puesto que cout y cin trabajan con la salida"

"y la entrada est ndar."

"2) La diferencia de usar cin >> s y de usar cin.getline () o cin.get ()"

"es que la primera versi¢n para de leer cuando se encuentra un car cter"

"espacio (correspondiente a la macro isspace() definida en ctype.h), un"

"car cter de nueva l¡nea o el car cter de fin de fichero, mientras que"

"las dos versiones anteriores paran de leer cuando nosotros queremos."

"Tambi‚n se puede observar que la funci¢n getline() lee los caracteres del"

"buffer y no del teclado pues se encuentra el texto " Lebr¢n Bocanegra

"seguido de un car cter de nueva l¡nea en el buffer."

"3) En la segunda parte de la funci¢n main() hay algunos conceptos intere-"

"santes. El primero de ellos es que por defecto, el indicador ios::skipws"

"est puesto a 1, por lo tanto, la sentencia cin.setf (ios::skipws) del"

"programa es innecesaria. Cuando este indicador est a 1, todos los primeros"

"caracteres de espacios blancos en la entrada son saltados. Por ejemplo, en"

"la salida se ve que se introduce " x" mientras que se almacena "x" en la"

"cadena de caracteres s. Sin embargo, en la segunda lectura, con el indicador"

"ios::skipws puesto a 0, los caracteres iniciales blancos no son saltados, y"

"por lo tanto, al encontrarse en primer lugar con un espacio blanco (ASCII"

"32) para de leer y la cadena s queda vac¡a. Tambi‚n es importante significar"

"que en la primera lectura, no s¢lo se introduce en el buffer de entrada los"

"caracteres espacio blanco y x (" x") sino tambi‚n un car cter de nueva l¡nea;"

"por ello, se utilizar el bucle while, para desechar este caracter; el bucle"

"while tambi‚n nos previene, por ejemplo, de la entrada " x y" desechando la"

"'y' y el car cter de nueva l¡nea, ya que si no, la segunda lectura empezar¡a"

"leyendo el espacio blanco que hay entre la x y la y."

*/

CLASE ostream_withassign "

" ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ"

" ostream_withassign ostream con un operador de asignaci¢n a¤adido"

" ßßßßßßßßßßßßßßßßßßßß"

" ÚÄÄÄÄÄÄÄÄÄ¿ ÛßßßßßßßßßßßßßßßßßßßßÛ ÚÄÄÄÄÄÄÄÄÄ¿"

" ³ ostream ÃÄÄÄÛ ostream_withassign ÛÄÄÄ´<ninguna>³"

" ÀÄÄÄÄÄÄÄÄÄÙ ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ ÀÄÄÄÄÄÄÄÄÄÙ"

"Declarada en: iostream.h"

" Constructores"

" ßßßßßßßßßßßßß"

"Constructor nulo (llama a constructor de ostream):"

" ostream_withassign ()"

" Funciones miembros"

" ßßßßßßßßßßßßßßßßßß"

" Ninguna (Aunque el operador = est sobrecargado)"

" Definici¢n"

" ßßßßßßßßßß"

"class ostream_withassign : public ostream"

{

" public:"

" // no inicializaci¢n"

" ostream_withassign ();"

" virtual ~ostream_withassign ();"

" // obtiene buffer de istream y hace inicializaci¢n completa"

" ostream_withassign& operator= (ostream&);"

" // asocia streambuf con flujo y hace inicializaci¢n completa"

" ostream_withassign& operator= (streambuf *);"

};

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Este ejemplo prueba la clase ostream_withassign."

"// EN REALIDAD, ESTE EJEMPLO MUESTRA COMO SOBRECARGAR LOS OPERDORES >> Y <<"

"// EN UNA CLASE DEFINIDA POR EL USUARIO"

"/*"

" El flujo cout es de tipo istream_withassign."

*/

"#include <iostream.h>"

"class vect"

{

" private:"

" int x, y;"

" public:"

" vect (int i = 0, int j = 0) { asig (i, j); }"

" void asig (int i, int j) { x = i; y = j; }"

" vect operator+ (void) { return *this; }"

" vect operator- (void) { return vect (-x, -y); }"

" friend vect operator+ (vect v1, vect v2)"

" { return vect (v1.x + v2.x, v1.y + v2.y); }"

" friend vect operator- (vect v1, vect v2)"

" { return v1 + -v2; }"

" friend ostream& operator<< (ostream& out, vect v)"

" { return out << '[' << v.x << ',' << v.y << ']'; }"

" friend istream& operator>> (istream& in, vect& v)"

" { return in >> '[' >> v.x >> ',' >> v.y >> ']'; }"

};

"void main (void)"

{

" vect vec, vec1 (1, 2), vec2 (-3);"

" cout << "\nvec1 = " << vec1 << " vec2 = " << vec2;"

" cout << "\n+vec1 - vec2 = " << vec1 - vec2;"

" cout << "\nIntroduce vec en la forma [x,y]: ";"

" cin >> vec;"

" cout << "vec: " << vec;"

}

"/*"

"SALIDA:"

"(r)"

"vec1 = [1,2] vec2 = [-3,0]"

"+vec1 - vec2 = [4,2]"

"Introduce vec en la forma [x,y]: [4,5]"

"vec: [4,5]"

"¯"

"OBSERVACIONES SOBRE LA SALIDA DEL PROGRAMA:"

"1) El primer [4,5] es introducido desde teclado y visualizado en pantalla."

"2) La l¡nea"

" cout << "vec: " << vec;"

"es equivalente a la l¡nea:"

" cout.operator<< ("vec: "); operator<< (cout, vec);"

"La direrencia de las dos llamadas anteriores a operator<< viene dada porque"

"la primera es una funci¢n miembro (ver definici¢n de clase ostream.h) y la"

"segunda es una funci¢n amiga (ver definici¢n de la clase vect m s arriba)."

"Los operadores << y >> son dos operadores binarios que se pueden sobrecargar"

"al igual que los dem s operadores sobrecargables. De hecho, los operadores"

"<< y >> ya est n sobrecargados en las clases istream y ostream para los tipos"

"definidos por el sistema."

"Cuando se hace:"

" cout << "a" << 'b';"

"se est haciendo en realidad:"

" (cout.operator<<("a")).operator<<('b');"

*/

CLASE iostream_withassign "

" ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ"

" iostream_withassign iostream con un operador de asignaci¢n a¤adido"

" ßßßßßßßßßßßßßßßßßßßßß"

" ÚÄÄÄÄÄÄÄÄÄÄ¿ ÛßßßßßßßßßßßßßßßßßßßßßÛ ÚÄÄÄÄÄÄÄÄÄÄÄ¿"

" ³ iostream ÃÄÄÄÄÛ iostream_withassign ÛÄÄÄÄ´ <ninguna> ³"

" ÀÄÄÄÄÄÄÄÄÄÄÙ ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ ÀÄÄÄÄÄÄÄÄÄÄÄÙ"

"Declarada en: iostream.h"

" Constructores"

" ßßßßßßßßßßßßß"

"Constructor nulo (llama a constructor de iostream):"

" iostream_withassign ()"

" Funciones miembros"

" ßßßßßßßßßßßßßßßßßß"

" Ninguna (Aunque el operador = est sobrecargado)"

" Definici¢n"

" ßßßßßßßßßß"

"class iostream_withassign : public iostream"

{

" public:"

" // no inicializaci¢n"

" iostream_withassign ();"

" virtual ~iostream_withassign ();"

" // obtiene buffer de stream y hace inicializaci¢n completa"

" iostream_withassign& operator= (ios&);"

" // asocia streambuf con flujo y hace inicializaci¢n completa"

" iostream_withassign& operator= (streambuf *);"

};

FICHERO iostream.h "

" ÜÜÜÜÜÜÜÜÜÜÜÜ"

" IOSTREAM.H"

" ßßßßßßßßßßßß"

"Declara los flujos b sicos."

"Reemplaza al viejo fichero de cabecera stream.h."

" Incluye"

" ßßßßßßß"

" mem.h"

" Clases"

" ßßßßßß"

" ios iostream iostream_withassign"

" istream istream_withassign ostream"

" ostream_withassign streambuf"

" Funciones"

" ßßßßßßßßß"

" allocate bad base blen cerr"

" cin clear cout dbp dec"

" do_sgetn do_snextc do_sputn doallocate eback"

" ebuf egptr endl ends eof"

" epptr fail fill flags flush"

" gbump gcount get getline good"

" gptr hex ignore in_avail oct"

" out_waiting overflow pbackfail pbase pbump"

" peek precision put putback read"

" sbumpc seekg seekoff seekp seekpos"

" setb setbuf setf setg setp"

" setstate sgetc sgetn skip snextc"

" sputbackc sputc sputn stossc sync"

" tellg tellp tie unbuffered underflow"

" unsetf width write ws"

" Constantes, tipos de datos, y variables globales"

" ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß"

" adjustfield (const) basefield (const) floatfield (const)"

" io_state (enum) open_mode (enum) seek_dir (enum)"

" streamoff (typedef) streampos (typedef)"

" Operadores sobrecargados"

" ßßßßßßßßßßßßßßßßßßßßßßßß"

" = >> <<"

" Contenido (abreviado):"

" ßßßßßßßßßßßßßßßßßßßßßß"

"// ..."

"#ifndef __IOSTREAM_H"

"#define __IOSTREAM_H"

"#if !defined( __MEM_H )"

"#include <mem.h> // obtiene memcpy y NULL"

"#endif"

"// ..."

"// Definici¢n de EOF que debe coincidir con la que se hace en <stdio.h>"

"#define EOF (-1)"

"// extrae un car cter de int i, asegurando que zapeof(EOF) != EOF"

"#define zapeof(i) ((unsigned char)(i))"

"typedef long streampos;"

"typedef long streamoff;"

"class streambuf;"

"class ostream;"

"class ios"

{

" // ..."

};

"class streambuf"

{

" // ..."

};

"class istream : virtual public ios"

{

" // ..."

};

"class ostream : virtual public ios"

{

" // ..."

};

"class iostream : public istream, public ostream"

{

" // ..."

};

"class istream_withassign : public istream"

{

" // ..."

};

"class ostream_withassign : public ostream"

{

" // ..."

};

"class iostream_withassign : public iostream"

{

" // ..."

};

"/*"

" * Los flujos predefinidos"

" */"

"extern istream_withassign cin;"

"extern ostream_withassign cout;"

"extern ostream_withassign cerr;"

"extern ostream_withassign clog;"

"/*"

" * Manipuladores"

" */"

"ostream& endl (ostream&); // inserta nueva l¡nea y vuelca"

"ostream& ends (ostream&); // inserta nulo para terminar string"

"ostream& flush (ostream&); // vuelca el flujo"

"ios& dec (ios&); // pone base de conversi¢n a decimal"

"ios& hex (ios&); // pone base de conversi¢n a hexadecimal"

"ios& oct (ios&); // pone base de conversi¢n a octal"

"istream& ws (istream&); // extrae caracteres de espacios blancos"

"#endif"

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Ejemplo sobre manipuladores."

"#include <iostream.h>"

"inline ostream& may (ostream& out)"

{

" return out.setf (ios::uppercase), out;"

}

"inline ostream& dosendl (ostream& out)"

{

" return out << endl << endl;"

}

"void main (void)"

{

" const int num = 10;"

" const char sp = ' ';"

" cout << dec << 10 << sp << hex << num << sp << may << num << sp"

" << oct << num << dosendl << flush;"

" int x;"

" const char *msj = "Introduce valor de x: ";"

" cout << msj;"

" cin >> ws >> x;"

" cout << "El valor de x es: " << x << ends;"

}

"/*"

"SALIDA:"

"(r)"

"10 a A 12"

"Introduce valor de x: 3"

"El valor de x es 3"

"¯"

"OBSERVACIONES SOBRE LA SALIDA DEL PROGRAMA:"

"1) El primer 3 es introducido desde teclado y visualizado en pantalla."

"2) Los manipuladores endl, ends, flush, dec, hex, oct y ws est n declarados"

"en el fichero iostream.h. Los manipuladores may y dosendl son manipuladores"

"definidos por el usuario. El manipulador ends es £til cuando la salida se"

"dirige hacia un string en vez de a pantalla o a fichero."

*/

CLASE filebuf "

" ÜÜÜÜÜÜÜÜÜ"

" filebuf Especializa streambuf para manipular ficheros."

" ßßßßßßßßß"

" ÚÄÄÄÄÄÄÄÄÄÄÄ¿ ÛßßßßßßßßßÛ ÚÄÄÄÄÄÄÄÄÄÄÄ¿"

" ³ streambuf ÃÄÄÄÛ filebuf ÛÄÄÄ´ <ninguna> ³"

" ÀÄÄÄÄÄÄÄÄÄÄÄÙ ÛÜÜÜÜÜÜÜÜÜÛ ÀÄÄÄÄÄÄÄÄÄÄÄÙ"

" Declarada en: fstream.h"

" Constructores"

" ßßßßßßßßßßßßß"

"Crea un filebuf que no es a¤adido a un fichero:"

" filebuf ()"

"Crea un filebuf a¤adido a un fichero v¡a un descriptor de fichero:"

" filebuf (int fd)"

"Crea un filebuf a¤adido a un fichero y usa el buffer de n caracteres"

"especificado:"

" filebuf (int fd, char *, int n)"

" Funciones miembros"

" ßßßßßßßßßßßßßßßßßß"

" attach close fd is_open open seekoff setbuf"

" Definici¢n"

" ßßßßßßßßßß"

"class filebuf : public streambuf"

{

" public:"

" static const int openprot; // protecci¢n del fichero por defecto"

" // constructores, destructor"

" filebuf (); // crea un filebuf cerrado"

" filebuf (int); // crea un filebuf a¤adido a fd"

" filebuf (int _f, char *, int); // igual, con buffer especificado"

" ~filebuf ();"

" int is_open (); // est el fichero abierto"

" int fd (); // cu l es el descriptor del fichero"

" // abre fichero nombrado con modo y protecci¢n, lo a¤ade a este filebuf"

" filebuf * open (const char *, int, int = filebuf::openprot );"

" filebuf * close (); // vuelca y cierra fichero"

" filebuf * attach (int); // a¤ade este filbuf al descriptor de fichero"

" // abierto"

" /*"

" * Ejecutan las funciones de streambuf sobre un filebuf"

" * Los punteros de lectura y escritura son guardados juntos"

" */"

" virtual int overflow (int = EOF);"

" virtual int underflow ();"

" virtual int sync ();"

" virtual streampos seekoff (streamoff, seek_dir, int);"

" virtual streambuf * setbuf (char *, int);"

" protected:"

" // ..."

};

" Descripci¢n de los m‚todos"

" ßßßßßßßßßßßßßßßßßßßßßßßßßß"

"ÜÜÜÜÜÜÜÜ"

" attach Funci¢n miembro"

"ßßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ A¤ade este filebuf cerrado al descriptor de fichero abierto:³"

"³ ³ filebuf* attach (int) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstreambase ³ Conecta a un descriptor de fichero abierto: ³"

"³ ³ void attach (int) ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜÜÜ"

" close Funci¢n miembro"

"ßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ Vuelca y cierra el fichero. Devuelve 0 en caso de error: ³"

"³ ³ filebuf* close () ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstreambase ³ Cierra el filebuf y fichero asociado: ³"

"³ ³ void close () ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜ"

" fd Funci¢n miembro"

"ßßßß"

"ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ Devuelve el descriptor de fichero o EOF: ³"

"³ ³ int fd () ³"

"ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜÜÜÜÜ"

" is_open Funci¢n miembro"

"ßßßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ Devuelve un valor distinto de cero si el fichero est abierto: ³"

"³ ³ int is_open() ³"

"ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜÜ"

" open Funci¢n miembro"

"ßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ Abre el fichero dado y se conecta a ‚l: ³"

"³ ³ filebuf* open (const char*, int mode, ³"

"³ ³ int prot = filebuf::openprot) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstream ³ Abre un fichero para un fstream: ³"

"³ fstreambase ³ Abre un fichero para un fstreambase: ³"

"³ ifstream ³ Abre un fichero para un ifstream: ³"

"³ ofstream ³ Abre un fichero para un ofstream: ³"

"³ ³ void open (const char*, int, int = filebuf::openprot) ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜÜÜÜÜ"

" seekoff Funci¢n miembro"

"ßßßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ Mueve el puntero de fichero relativo a la posici¢n actual: ³"

"³ ³ virtual long seekoff (long, seek_dir, int) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ streambuf ³ Mueve el puntero de lectura y/o escritura (el tercer ³"

"³ ³ argumento determina cu l o si son ambos) relativo a la ³"

"³ ³ posici¢n actual: ³"

"³ ³ virtual long seekoff (long, seek_dir, ³"

"³ ³ int = (ios::in | ios::out)) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ strstreambuf ³ Mueve el puntero relativo a la posici¢n actual: ³"

"³ ³ virtual long seekoff (long, seek_dir, int) ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜÜÜÜ"

" setbuf Funci¢n miembro"

"ßßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ Especifica el buffer a usar: ³"

"³ strstreambuf ³ virtual streambuf* setbuf (char*, int) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstreambase ³ Usa un buffer especificado: ³"

"³ ³ void setbuf (char*, int) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ streambuf ³ Conecta a un buffer dado: ³"

"³ ³ virtual streambuf* setbuf (signed char*, int) ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Ejemplo sobre la clase filebuf."

"#include <iostream.h>"

"#include <fstream.h>"

"void main (void)"

{

" ofstream fich;"

" fich.open ("PRUEBA.TXT");"

" cout << "¨Est abierto?: " << (fich.rdbuf())->is_open() << endl"

" << "Descriptor de fichero: " << (fich.rdbuf())->fd();"

" fich.close ();"

}

"/*"

"SALIDA:"

"(r)"

"¨Est abierto?: 1"

"Descriptor de fichero: 8"

"¯"

"OBSERVACIONES SOBRE LA SALIDA DEL PROGRAMA:"

"1) El n£mero del descriptor de fichero es dependiente del sistema."

"2) La clase ofstream la veremos un poco m s adelante. En este ejemplo, el"

"objeto fich es un fichero de escritura. La clase filebuf no se suele usar"

"directamente sino a trav‚s de sus clases derivadas tal y como hemos hecho"

"en este programa."

*/

CLASE fstreambase "

" ÜÜÜÜÜÜÜÜÜÜÜÜÜ"

" fstreambase Proporciona operaciones comunes a los flujos de fichero."

" ßßßßßßßßßßßßß"

" ÚÄÄÄÄÄÄÄÄÄÄ¿"

" ÚÄ´ fstream ³"

" ÚÄÄÄÄÄ¿ ÛßßßßßßßßßßßßßÛÄÄÙ ÆÍÍÍÍÍÍÍÍÍ͵"

" ³ ios ÃÄÄÄÛ fstreambase ÛÄÄÄÄ´ ifstream ³"

" ÀÄÄÄÄÄÙ ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÛÄÄ¿ ÆÍÍÍÍÍÍÍÍÍ͵"

" ÀÄ´ ofstream ³"

" ÀÄÄÄÄÄÄÄÄÄÄÙ"

"Declarada en: fstream.h"

" Constructores"

" ßßßßßßßßßßßßß"

"Crea un fstreambase que no es a¤adido a un fichero:"

" fstreambase ()"

"Crea un fstreambase, abre un fichero, y lo conecta a ‚l:"

" fstreambase (const char*, int, int = filebuf::openprot)"

"Crea un fstreambase, lo conecta a un descriptor de fichero abierto:"

" fstreambase (int)"

"Crea un fstreambase conectado a un fichero abierto, usa el buffer"

"especializado:"

" fstreambase (int _f, char*, int)"

" Funciones miembros"

" ßßßßßßßßßßßßßßßßßß"

" attach close open rdbuf setbuf"

" Definici¢n"

" ßßßßßßßßßß"

"class fstreambase : virtual public ios"

{

" public:"

" fstreambase ();"

" fstreambase (const char *, int, int = filebuf::openprot);"

" fstreambase (int);"

" fstreambase (int _f, char *, int);"

" ~fstreambase ();"

" void open (const char *, int, int = filebuf::openprot);"

" void attach (int);"

" void close ();"

" void setbuf (char *, int);"

" filebuf * rdbuf ();"

" protected:"

" // ..."

" private:"

" // ..."

};

" Descripci¢n de los m‚todos"

" ßßßßßßßßßßßßßßßßßßßßßßßßßß"

"ÜÜÜÜÜÜÜÜ"

" attach Funci¢n miembro"

"ßßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ A¤ade este filebuf cerrado al descriptor de fichero abierto:³"

"³ ³ filebuf* attach (int) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstreambase ³ Conecta a un descriptor de fichero abierto: ³"

"³ ³ void attach (int) ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜÜÜ"

" close Funci¢n miembro"

"ßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ Vuelca y cierra el fichero. Devuelve 0 en caso de error: ³"

"³ ³ filebuf* close () ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstreambase ³ Cierra el filebuf y fichero asociado: ³"

"³ ³ void close () ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜÜ"

" open Funci¢n miembro"

"ßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ Abre el fichero dado y se conecta a ‚l: ³"

"³ ³ filebuf* open (const char*, int mode, ³"

"³ ³ int prot = filebuf::openprot) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstream ³ Abre un fichero para un fstream: ³"

"³ fstreambase ³ Abre un fichero para un fstreambase: ³"

"³ ifstream ³ Abre un fichero para un ifstream: ³"

"³ ofstream ³ Abre un fichero para un ofstream: ³"

"³ ³ void open (const char*, int, int = filebuf::openprot) ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜÜÜ"

" rdbuf Funci¢n miembro"

"ßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ ios ³ Devuelve un puntero al streambuf asignado a este flujo: ³"

"³ ³ streambuf* rdbuf () ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstream ³ Devuelve el buffer usado: ³"

"³ fstreambase ³ filebuf* rdbuf () ³"

"³ ifstream ³ ³"

"³ ofstream ³ ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜÜÜÜ"

" setbuf Funci¢n miembro"

"ßßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ Especifica el buffer a usar: ³"

"³ strstreambuf ³ virtual streambuf* setbuf (char*, int) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstreambase ³ Usa un buffer especificado: ³"

"³ ³ void setbuf (char*, int) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ streambuf ³ Conecta a un buffer dado: ³"

"³ ³ virtual streambuf* setbuf (signed char*, int) ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Ejemplo sobre la clase fstreambase."

"#include <iostream.h>"

"#include <fstream.h>"

"void main (void)"

{

" ofstream fich;"

" fich.open ("PRUEBA.TXT");"

" cout << (fich.rdbuf () == fich.fstreambase::rdbuf ());"

" fich.close ();"

}

"/*"

"SALIDA:"

"(r)"

"1"

"¯"

"OBSERVACIONES SOBRE EL PROGRAMA:"

"1) La clase fstreambase es clase base de las clases ifstream, ofstream y"

"fstream. Esta clase base no se suele usar directamente sino que sirve"

"simplemente como clase base de las tres clases mencionadas."

"2) La funci¢n ofstream::rdbuf() est implementada como una funci¢n inline"

"que lo £nico que hace es realizar la llamada fstreambase::rdbuf()."

*/

CLASE ifstream "

" ÜÜÜÜÜÜÜÜÜÜ"

" ifstream Proporciona operaciones de entrada sobre un filebuf."

" ßßßßßßßßßß"

" ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

" ³ fstreambase ÃÄÄ¿ ÛßßßßßßßßßßÛ ÚÄÄÄÄÄÄÄÄÄÄÄ¿"

" ÆÍÍÍÍÍÍÍÍÍÍÍÍ͵ ÃÄÄÄÛ ifstream ÛÄÄÄÄ´ <ninguna> ³"

" ³ istream ÃÄÄÙ ÛÜÜÜÜÜÜÜÜÜÜÛ ÀÄÄÄÄÄÄÄÄÄÄÄÙ"

" ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"Declarada en: fstream.h"

" Constructores"

" ßßßßßßßßßßßßß"

"Crea un ifstream que no es a¤adido a un fichero:"

" ifstream ()"

"Crea un ifstream, abre un fichero, y lo conecta a ‚l:"

" ifstream (const char*, int, int = filebuf::openprot)"

"Crea un ifstream, lo conecta a un descriptor de fichero abierto:"

" ifstream(int)"

"Crea un ifstream, conectado a un fichero abierto y usa un buffer"

"especificado:"

" ifstream(int fd, char*, int)"

" Funciones miembros"

" ßßßßßßßßßßßßßßßßßß"

" open rdbuf"

" Definici¢n"

" ßßßßßßßßßß"

"class ifstream : public fstreambase, public istream"

{

" public:"

" ifstream ();"

" ifstream (const char *, int = ios::in, int = filebuf::openprot);"

" ifstream (int);"

" ifstream (int _f, char *, int);"

" ~ifstream ();"

" filebuf * rdbuf ();"

" void open (const char *, int = ios::in, int = filebuf::openprot);"

};

" Descripci¢n de los m‚todos"

" ßßßßßßßßßßßßßßßßßßßßßßßßßß"

"ÜÜÜÜÜÜ"

" open Funci¢n miembro"

"ßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ Abre el fichero dado y se conecta a ‚l: ³"

"³ ³ filebuf* open (const char*, int mode, ³"

"³ ³ int prot = filebuf::openprot) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstream ³ Abre un fichero para un fstream: ³"

"³ fstreambase ³ Abre un fichero para un fstreambase: ³"

"³ ifstream ³ Abre un fichero para un ifstream: ³"

"³ ofstream ³ Abre un fichero para un ofstream: ³"

"³ ³ void open (const char*, int, int = filebuf::openprot) ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜÜÜ"

" rdbuf Funci¢n miembro"

"ßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ ios ³ Devuelve un puntero al streambuf asignado a este flujo: ³"

"³ ³ streambuf* rdbuf () ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstream ³ Devuelve el buffer usado: ³"

"³ fstreambase ³ filebuf* rdbuf () ³"

"³ ifstream ³ ³"

"³ ofstream ³ ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Ejemplo sobre la clase ifstream."

"#include <iostream.h>"

"#include <fstream.h>"

"inline void error_apertura (const char *nomfich)"

{

" cout << "No se puede abrir el fichero " << nomfich << endl;"

}

"inline void error_cierre (const char *nomfich)"

{

" cout << "No se puede cerrar el fichero " << nomfich << endl;"

}

"void main (void)"

{

" // APERTURAS DE FICHEROS DE TEXTO"

" // Forma 1 de abrir fichero:"

" ifstream f1;"

" f1.open ("FICH1.TXT");"

" // Forma 2 de abrir fichero:"

" ifstream f2 ("FICH2.TXT");"

" // Forma 1 de comprobar apertura:"

" if (f1.fail ()) // o tambi‚n se puede hacer: if (! f1.good ())"

" error_apertura ("FICH1.TXT");"

" // Forma 2 de comprobar apertura:"

" if (! f2)"

" error_apertura ("FICH2.TXT");"

" // APERTURA DE FICHERO BINARIO"

" ifstream f3 ("FICH3.TXT", ios::binary);"

" if (! f3)"

" error_apertura ("FICH3.TXT");"

" // CIERRE DE LOS FICHEROS ABIERTOS"

" f1.close ();"

" if (! f1)"

" error_cierre ("FICH1.TXT");"

" f2.close ();"

" if (! f2)"

" error_cierre ("FICH2.TXT");"

" f3.close ();"

" if (! f3)"

" error_cierre ("FICH3.TXT");"

}

"/*"

"SALIDA:"

"(r)"

"No se puede abrir el fichero FICH1.TXT"

"No se puede abrir el fichero FICH2.TXT"

"No se puede abrir el fichero FICH3.TXT"

"No se puede cerrar el fichero FICH1.TXT"

"No se puede cerrar el fichero FICH2.TXT"

"No se puede cerrar el fichero FICH3.TXT"

"¯"

"OBSERVACIONES SOBRE EL PROGRAMA:"

"1) Los errores se han producido al ejecutar este programa porque ninguno de"

"los tres ficheros de lectura (FICH1.TXT, FICH2.TXT y FICH3.TXT) existen en"

"disco."

"2) Despu‚s de cada operaci¢n que se haga sobre un fichero se puede hacer la"

"comprobaci¢n de operaci¢n correcta. Ejemplo:"

" ch = f1.get ();"

" if (! f1)"

" error ();"

"Todas las funciones de la clase istream (y de sus clases bases como ios)"

"est n a disposici¢n de la clase ifstream. De esta forma, podemos leer del"

"fichero utilizando las funciones como get(), getline(), read() o el operador"

"sobrecargado >>."

"Aunque el usuario no tiene porqu‚ saber c¢mo est n implementadas las funcio-"

"nes de una clase sino solamente su interface, diremos que el operador ! est "

"sobrecargado en la clase ios de la siguiente forma:"

"inline int ios::operator! () { return fail (); }"

"3) En la clase ifstream, si no se especifica el segundo par metro de la fun-"

"ci¢n open() o bien del constructor, ‚ste es por defecto: ios::in."

"4) Todo lo dicho en estas observaciones tambi‚n se puede aplicar a la clase"

"ofstream que veremos a continuaci¢n, cambiando las funciones de lectura por"

"funciones de escritura y cambiando el modo de operaci¢n por defecto ios::in"

"al modo ios::out."

*/

CLASE ofstream "

" ÜÜÜÜÜÜÜÜÜÜ"

" ofstream Proporciona operaciones de salida sobre un filebuf."

" ßßßßßßßßßß"

" ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

" ³ fstreambase ÃÄÄ¿ ÛßßßßßßßßßßÛ ÚÄÄÄÄÄÄÄÄÄÄÄ¿"

" ÆÍÍÍÍÍÍÍÍÍÍÍÍ͵ ÃÄÄÄÛ ofstream ÛÄÄÄ´ <ninguna> ³"

" ³ ostream ÃÄÄÙ ÛÜÜÜÜÜÜÜÜÜÜÛ ÀÄÄÄÄÄÄÄÄÄÄÄÙ"

" ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"Declarada en: fstream.h"

" Constructores"

" ßßßßßßßßßßßßß"

"Crea un ofstream que no es a¤adido a un fichero:"

" ofstream ()"

"Crea un ofstream, abre un fichero, y lo conecta a ‚l:"

" ofstream (const char*, int, int = filebuf::openprot)"

"Crea un ifstream, lo conecta a un descriptor de fichero abierto:"

" ofstream (int)"

"Crea un ifstream, conectado a un fichero abierto y usa un buffer"

"especificado:"

" ofstream (int fd, char*, int)"

" Funciones miembros"

" ßßßßßßßßßßßßßßßßßß"

" open rdbuf"

" Definici¢n"

" ßßßßßßßßßß"

"class ofstream : public fstreambase, public ostream"

{

" public:"

" ofstream ();"

" ofstream (const char *, int = ios::out, int = filebuf::openprot);"

" ofstream (int);"

" ofstream (int _f, char *, int);"

" ~ofstream ();"

" filebuf * rdbuf ();"

" void open(const char *, int = ios::out, int = filebuf::openprot);"

};

" Descripci¢n de los m‚todos"

" ßßßßßßßßßßßßßßßßßßßßßßßßßß"

"ÜÜÜÜÜÜ"

" open Funci¢n miembro"

"ßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ Abre el fichero dado y se conecta a ‚l: ³"

"³ ³ filebuf* open (const char*, int mode, ³"

"³ ³ int prot = filebuf::openprot) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstream ³ Abre un fichero para un fstream: ³"

"³ fstreambase ³ Abre un fichero para un fstreambase: ³"

"³ ifstream ³ Abre un fichero para un ifstream: ³"

"³ ofstream ³ Abre un fichero para un ofstream: ³"

"³ ³ void open (const char*, int, int = filebuf::openprot) ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜÜÜ"

" rdbuf Funci¢n miembro"

"ßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ ios ³ Devuelve un puntero al streambuf asignado a este flujo: ³"

"³ ³ streambuf* rdbuf () ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstream ³ Devuelve el buffer usado: ³"

"³ fstreambase ³ filebuf* rdbuf () ³"

"³ ifstream ³ ³"

"³ ofstream ³ ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Ejemplo sobre la clase ofstream."

"#include <iostream.h>"

"#include <fstream.h>"

"inline void error_apertura (const char *nomfich)"

{

" cout << "No se puede abrir el fichero " << nomfich << endl;"

}

"void main (void)"

{

" ofstream f1 ("FICH1.TXT");"

" if (! f1)"

" error_apertura ("FICH1.TXT");"

" ofstream f2 ("FICH2.TXT", ios::binary);"

" if (! f2)"

" error_apertura ("FICH2.TXT");"

" ofstream f3 ("FICH3.TXT", ios::app);"

" if (! f3)"

" error_apertura ("FICH3.TXT");"

" ofstream f4 ("FICH4.TXT", ios::app | ios::binary);"

" if (! f4)"

" error_apertura ("FICH4.TXT");"

" ofstream f5 ("FICH5.TXT", ios::nocreate);"

" if (! f5)"

" error_apertura ("FICH5.TXT");"

" ofstream f6 ("FICH6.TXT", ios::noreplace);"

" if (! f6)"

" error_apertura ("FICH6.TXT");"

" ofstream f7 ("FICH7.TXT", ios::nocreate | ios::noreplace);"

" if (! f7)"

" error_apertura ("FICH7.TXT");"

" ofstream f8 ("FICH8.TXT", ios::ate);"

" if (! f8)"

" error_apertura ("FICH8.TXT");"

" ofstream f9 ("FICH9.TXT", ios::trunc);"

" if (! f9)"

" error_apertura ("FICH9.TXT");"

" f1.close ();"

" f2.close ();"

" f3.close ();"

" f4.close ();"

" f5.close ();"

" f6.close ();"

" f7.close ();"

" f8.close ();"

" f9.close ();"

}

"/*"

"SALIDA:"

"(r)"

"No se puede abrir el fichero FICH5.TXT"

"No se puede abrir el fichero FICH7.TXT"

"¯"

"OBSERVACIONES SOBRE EL PROGRAMA:"

"1) Se ha producido error de apertura en FICH5.TXT porque ‚ste no existe"

"en el disco. Sin embargo, con el fichero FICH7.TXT siempre se producir "

"un error de apertura: si existe el fichero, hay error debido a ios::"

"noreplace, y si no existe el fichero, hay error debido a ios::nocreate."

"Por defecto, el fichero es abierto con modo de operaci¢n ios::out, esto"

"quiere decir, que tanto exista como no exista el fichero, se crea uno"

"nuevo; con los modos de operaci¢n se puede modificar esta situaci¢n. Lo"

"mismo ocurre con el modo texto que es el que est por defecto; para tra-"

"bajar con ficheros binarios, es necesario el indicador ios::binary. Con"

"el modo ios::app las escrituras en el fichero siempre se hacen al final"

"de ‚ste; con el modo ios::ate se pueden hacer en cualquier lugar usando"

"el m‚todo seekp(). Si se abre el fichero con el modo ios::trunc se des-"

"carta el contenido actual del fichero si ‚ste existe, o se crea un fi-"

"chero nuevo si no existe."

"2) Podemos escribir en los ficheros abiertos anteriormente haciendo, por"

"ejemplo:"

" f1 << 'x';"

"o utilizando los m‚todos de escritura tales como write() o put()."

"En resumen, podemos utilizar todas las funciones p£blicas de la clase"

"ostream, y por lo tanto, tambi‚n de la clase ios. La otra clase base"

"de ostream es fstreambase."

*/

CLASE fstream "

" ÜÜÜÜÜÜÜÜÜ"

" fstream Proporciona entrada y salida simult nea sobre un filebuf."

" ßßßßßßßßß"

" ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

" ³ fstreambase ÃÄÄ¿ ÛßßßßßßßßßÛ ÚÄÄÄÄÄÄÄÄÄÄÄ¿"

" ÆÍÍÍÍÍÍÍÍÍÍÍÍ͵ ÃÄÄÄÛ fstream ÛÄÄÄ´ <ninguna> ³"

" ³ iostream ÃÄÄÙ ÛÜÜÜÜÜÜÜÜÜÛ ÀÄÄÄÄÄÄÄÄÄÄÄÙ"

" ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

" Declarada en: fstream.h"

" Constructores"

" ßßßßßßßßßßßßß"

"Crea un fstream que no es a¤adido a un fichero:"

" fstream ()"

"Crea un fstream, abre un fichero, y lo conecta a ‚l:"

" fstream (const char*, int, int = filebuf::openprot)"

"Crea un fstream, lo conecta a un descriptor de fichero abierto:"

" fstream (int)"

"Crea un fstream, conectado a un fichero abierto y usa un buffer especificado:"

" fstream (int _f, char*, int)"

" Funciones miembros"

" ßßßßßßßßßßßßßßßßßß"

" open rdbuf"

" Definici¢n"

" ßßßßßßßßßß"

"class fstream : public fstreambase, public iostream"

{

" public:"

" fstream ();"

" fstream (const char *, int, int = filebuf::openprot);"

" fstream (int);"

" fstream (int _f, char *, int);"

" ~fstream ();"

" filebuf * rdbuf ();"

" void open (const char *, int, int = filebuf::openprot);"

};

" Descripci¢n de los m‚todos"

" ßßßßßßßßßßßßßßßßßßßßßßßßßß"

"ÜÜÜÜÜÜ"

" open Funci¢n miembro"

"ßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ Abre el fichero dado y se conecta a ‚l: ³"

"³ ³ filebuf* open (const char*, int mode, ³"

"³ ³ int prot = filebuf::openprot) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstream ³ Abre un fichero para un fstream: ³"

"³ fstreambase ³ Abre un fichero para un fstreambase: ³"

"³ ifstream ³ Abre un fichero para un ifstream: ³"

"³ ofstream ³ Abre un fichero para un ofstream: ³"

"³ ³ void open (const char*, int, int = filebuf::openprot) ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜÜÜ"

" rdbuf Funci¢n miembro"

"ßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ ios ³ Devuelve un puntero al streambuf asignado a este flujo: ³"

"³ ³ streambuf* rdbuf () ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstream ³ Devuelve el buffer usado: ³"

"³ fstreambase ³ filebuf* rdbuf () ³"

"³ ifstream ³ ³"

"³ ofstream ³ ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Ejemplo sobre la clase fstream."

"#include <iostream.h>"

"#include <fstream.h>"

"inline void error_apertura (const char *nomfich)"

{

" cout << "No se puede abrir el fichero " << nomfich << endl;"

}

"void main (void)"

{

" fstream f ("FICH.TXT", ios::in | ios::out);"

" if (! f)"

" error_apertura ("FICH.TXT");"

" f.close ();"

}

"/*"

"SALIDA:"

"(r)"

"¯"

"OBSERVACIONES SOBRE EL PROGRAMA:"

"1) Este programa no escribe nada porque no se produce error de apertura."

"2) La clase fstream se suele utilizar para trabajar con ficheros de lectura"

"y escritura."

"3) Por supuesto, se pueden a¤adir todos los indicadores de modos de opera-"

"ci¢n que se deseen, tales como ios::nocreate para que la operaci¢n de aper-"

"tura falle si el fichero no existe, o ios::binary para abrir un fichero bi-"

"nario puesto que por defecto se abre el fichero en modo texto, o ios::nore-"

"place para que la operaci¢n de apertura falle si el fichero ya existe, etc."

*/

FICHERO fstream.h "

" ÜÜÜÜÜÜÜÜÜÜÜ"

" FSTREAM.H"

" ßßßßßßßßßßß"

"Declara las clases de flujos de C++ que soportan entrada y salida de"

"ficheros."

" Incluye"

" ßßßßßßß"

" iostream.h"

" Clases"

" ßßßßßß"

" filebuf fstream fstreambase ifstream ofstream"

" Constantes, tipos de datos, y variables globales"

" ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß"

" _FSTREAM_H_"

" Contenido (abreviado):"

" ßßßßßßßßßßßßßßßßßßßßßß"

"#ifndef __FSTREAM_H"

"#define __FSTREAM_H"

"#if !defined( __IOSTREAM_H )"

"#include <iostream.h>"

"#endif"

"class filebuf : public streambuf"

{

" // ..."

};

"class fstreambase : virtual public ios"

{

" // ..."

};

"class ifstream : public fstreambase, public istream"

{

" // ..."

};

"class ofstream : public fstreambase, public ostream"

{

" // ..."

};

"class fstream : public fstreambase, public iostream"

{

" // ..."

};

"#endif"

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"En el segundo ejemplo que se encuentra en la tarea de ejemplos de esta"

"lecci¢n se encuentra un programa bastante instructivo que hace uso de"

"las clases ifstream y ofstream: programa que copia un fichero en otro"

"sitio del disco."

CLASE strstreambuf "

" ÜÜÜÜÜÜÜÜÜÜÜÜÜÜ"

" strstreambuf Especializa streambuf para formatos en memoria."

" ßßßßßßßßßßßßßß"

" ÚÄÄÄÄÄÄÄÄÄÄÄ¿ ÛßßßßßßßßßßßßßßÛ ÚÄÄÄÄÄÄÄÄÄÄÄ¿"

" ³ streambuf ÃÄÄÄÛ strstreambuf ÛÄÄÄ´ <ninguna> ³"

" ÀÄÄÄÄÄÄÄÄÄÄÄÙ ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ ÀÄÄÄÄÄÄÄÄÄÄÄÙ"

"Declarada en: strstrea.h"

" Constructores"

" ßßßßßßßßßßßßß"

"Crea un strstreambuf din mico:"

" strstreambuf ()"

" Ser asignada memoria din micamente conforme sea necesaria."

"Crea un buffer din mico con funciones de asignaci¢n y liberaci¢n"

"especificadas."

" strstreambuf (void * (*)(long), void * (*)(void *))"

"Crea un strstreambuf din mico, inicialmente se asigna un buffer de n bytes"

"como m¡nimo:"

" strstreambuf (int n)"

"Crea un strstreambuf est tico con un buffer especificado:"

" strstreambuf (char *, int, char *end)"

" Si en no es nulo, ‚l delimita el buffer."

" Funciones miembros"

" ßßßßßßßßßßßßßßßßßß"

" freeze str setbuf seekoff"

" Definici¢n"

" ßßßßßßßßßß"

"class strstreambuf : public streambuf"

{

" public:"

" strstreambuf ();"

" strstreambuf (int n);"

" strstreambuf (void * (*a) (long), void (*f) (void *));"

" strstreambuf (signed char * _s, int, signed char * _strt = 0);"

" strstreambuf (unsigned char * _s, int, unsigned char * _strt = 0);"

" ~strstreambuf ();"

" void freeze (int = 1);"

" char * str ();"

" virtual int doallocate ();"

" virtual int overflow (int);"

" virtual int underflow ();"

" virtual streambuf * setbuf (char *, int);"

" virtual streampos seekoff (streamoff, seek_dir, int);"

" private:"

" // ..."

};

" Descripci¢n de los m‚todos"

" ßßßßßßßßßßßßßßßßßßßßßßßßßß"

"ÜÜÜÜÜÜÜÜ"

" freeze Funci¢n miembro"

"ßßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ strstreambuf ³ Si el par metro de entrada es distinto de cero, no permite ³"

"³ ³ almacenar caracteres en el buffer; realiza la operaci¢n ³"

"³ ³ contraria pasando un cero: ³"

"³ ³ void freeze (int = 1) ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜ"

" str Funci¢n miembro"

"ßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ ostrstream ³ Devuelve y congela (freeze) el buffer: ³"

"³ strstream ³ char *str () ³"

"³ ³ Debes liberar el buffer si es din mico. ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ strstreambuf ³ Devuelve un puntero al buffer y lo congela (freeze): ³"

"³ ³ char *str () ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜÜÜÜ"

" setbuf Funci¢n miembro"

"ßßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ Especifica el buffer a usar: ³"

"³ strstreambuf ³ virtual streambuf* setbuf (char*, int) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ fstreambase ³ Usa un buffer especificado: ³"

"³ ³ void setbuf (char*, int) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ streambuf ³ Conecta a un buffer dado: ³"

"³ ³ virtual streambuf* setbuf (signed char*, int) ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜÜÜÜÜ"

" seekoff Funci¢n miembro"

"ßßßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ filebuf ³ Mueve el puntero de fichero relativo a la posici¢n actual: ³"

"³ ³ virtual long seekoff (long, seek_dir, int) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ streambuf ³ Mueve el puntero de lectura y/o escritura (el tercer ³"

"³ ³ argumento determina cu l de los dos o ambos) relativo ³"

"³ ³ a la posici¢n actual: ³"

"³ ³ virtual long seekoff (long, seek_dir, ³"

"³ ³ int = (ios::in | ios::out)) ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ strstreambuf ³ Mueve el puntero relativo a la posici¢n actual: ³"

"³ ³ virtual long seekoff(long, seek_dir, int) ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Ejemplo sobre la clase strstreambuf."

"#include <iostream.h>"

"#include <strstream.h>"

"void main (void)"

{

" const int tam = 100;"

" char buf[tam];"

" ostrstream s (buf, tam);"

" s << "abc" << ends;"

" cout << buf << ' '<< (s.rdbuf())->str();"

}

"/*"

"SALIDA:"

"(r)"

"abc abc"

"¯"

"OBSERVACIONES SOBRE EL PROGRAMA:"

"1) La clase ostrstream se explicar un poco m s adelante pero era necesario"

"utilizarla aqu¡ puesto que la clase strstreambuf no se suele utilizar direc-"

"tamente."

"2) El m‚todo str() que se ejecuta es el de la clase strstreambuf. Como se"

"ver m s adelante, este m‚todo lo posee la clase ostrstream, con lo cual"

"se pod¡a haber hecho directamente: s.str(). Aunque la forma m s f cil de"

"acceder al buffer es utilizando directamente el mismo buffer si se dispone"

"de ‚l como es ‚ste el caso: buf."

"3) El manipulador ends es necesario, ya que si no se hace, no hay car cter"

"nulo en buf que delimite el final de la cadena de caracteres."

*/

CLASE strstreambase "

" ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ"

" strstreambase Especializa ios para flujos de strings."

" ßßßßßßßßßßßßßßß"

" ÚÄÄÄÄÄÄÄÄÄÄÄÄ¿"

" ÚÄ´ istrstream ³"

" ÚÄÄÄÄÄ¿ ÛßßßßßßßßßßßßßßßÛ ³ ÆÍÍÍÍÍÍÍÍÍÍÍ͵"

" ³ ios ÃÄÄÄÛ strstreambase ÛÄÄÅÄ´ ostrstream ³"

" ÀÄÄÄÄÄÙ ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ ³ ÆÍÍÍÍÍÍÍÍÍÍÍ͵"

" ÀÄ´ strstream ³"

" ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"Declarada en: strstrea.h"

" Constructores"

" ßßßßßßßßßßßßß"

"Crea un strstreambase vac¡o:"

" strstreambase ()"

"Crea un strstreambase con un buffer y posici¢n de comienzo especificados:"

" strstreambase (const char*, int, char *start)"

" Funciones miembros"

" ßßßßßßßßßßßßßßßßßß"

" Ninguna (usa ios)"

" Definici¢n"

" ßßßßßßßßßß"

"class strstreambase : public virtual ios"

{

" public:"

" strstreambuf * rdbuf ();"

" protected:"

" strstreambase (char *, int, char *);"

" strstreambase ();"

" ~strstreambase ();"

" private:"

" strstreambuf buf;"

};

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Ejemplo sobre la clase strstreambase."

"#include <iostream.h>"

"#include <strstream.h>"

"void main (void)"

{

" const int tam = 100;"

" char buf[tam];"

" ostrstream s (buf, tam);"

" s << "abc" << ends;"

" cout << buf << ' '<< (s.strstreambase::rdbuf())->str();"

}

"/*"

"SALIDA:"

"(r)"

"abc abc"

"¯"

"OBSERVACIONES SOBRE EL PROGRAMA:"

"1) La clase ostrstream se explicar un poco m s adelante pero era necesario"

"utilizarla aqu¡ puesto que la clase strstreambase no se suele utilizar"

"directamente sino como clase base de las clases istrstream, ostrstream y"

"strstream."

"2) El m‚todo rdbuf() que se ejecuta es el de la clase strstreambase. Como"

"se ver m s adelante, este m‚todo lo posee la clase ostrstream, con lo cual"

"se pod¡a haber hecho directamente: s.rdbuf()."

*/

CLASE istrstream "

" ÜÜÜÜÜÜÜÜÜÜÜÜ"

" istrstream Proporciona operaciones de entrada sobre un strstreambuf."

" ßßßßßßßßßßßß"

" ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

" ³ strstreambase ÃÄÄ¿ ÛßßßßßßßßßßßßÛ ÚÄÄÄÄÄÄÄÄÄÄÄ¿"

" ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵ ÃÄÄÄÛ istrstream ÛÄÄÄ´ <ninguna> ³"

" ³ istream ÃÄÄÙ ÛÜÜÜÜÜÜÜÜÜÜÜÜÛ ÀÄÄÄÄÄÄÄÄÄÄÄÙ"

" ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"Declarada en: strstrea.h"

" Constructores"

" ßßßßßßßßßßßßß"

"Crea un istrstream con un string especificado (el car cter nulo nunca se"

"extrae):"

" istrstream (const char *)"

"Crea un istrstream usando n bytes de un string especificado:"

" istrstream (const char *, int n)"

" Funciones miembros"

" ßßßßßßßßßßßßßßßßßß"

" Ninguna"

" Definici¢n"

" ßßßßßßßßßß"

"class istrstream : public strstreambase, public istream"

{

" public:"

" istrstream (char *);"

" istrstream (char *, int);"

" ~istrstream ();"

};

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Ejemplo sobre la clase istrstream."

"#include <iostream.h>"

"#include <strstream.h>"

"#include <stdlib.h>"

"inline void error (const char *nomclase)"

{

" cerr << "Error en clase " << nomclase;"

" exit (1);"

}

"void main (void)"

{

" char *buf = "Ejemplo de la clase istrstream.";"

" istrstream s1 (buf);"

" if (! s1)"

" error ("s1");"

" istrstream s2 (buf, 5);"

" if (! s2)"

" error ("s2");"

" char ch, str[20];"

" s1 >> ch >> str;"

" cout << ch << str << endl;"

" s2 >> ch >> str;"

" cout << ch << str << endl;"

}

"/*"

"SALIDA:"

"(r)"

"Ejemplo"

"Ejemp"

"¯"

"OBSERVACIONES SOBRE EL PROGRAMA:"

"1) Con la clase istrstream se trabaja de una forma similar que con la clase"

"ifstream, con la diferencia de que en istrstream se lee de un string y en"

"ifstream se lee de un fichero."

*/

CLASE ostrstream "

" ÜÜÜÜÜÜÜÜÜÜÜÜ"

" ostrstream Proporciona operaciones de salida sobre un strstreambuf."

" ßßßßßßßßßßßß"

" ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

" ³ strstreambase ÃÄÄ¿ ÛßßßßßßßßßßßßÛ ÚÄÄÄÄÄÄÄÄÄÄÄ¿"

" ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵ ÃÄÄÄÛ istrstream ÛÄÄÄ´ <ninguna> ³"

" ³ istream ÃÄÄÙ ÛÜÜÜÜÜÜÜÜÜÜÜÜÛ ÀÄÄÄÄÄÄÄÄÄÄÄÙ"

" ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"Declarada en: strstrea.h"

" Constructors"

" ßßßßßßßßßßßß"

"Crea un ostrstream din mico:"

" ostrstream ()"

"Crea un ostrstream con un buffer de n bytes especificado:"

" ostrstream (char*, int, int)"

" Si el modo es ios::app o ios::ate, el puntero de lectura/escritura"

" es posicionado en el car cter nul del string."

" Funciones miembros"

" ßßßßßßßßßßßßßßßßßß"

" pcount str"

" Definici¢n"

" ßßßßßßßßßß"

"class ostrstream : public strstreambase, public ostream"

{

" public:"

" ostrstream (char *, int, int = ios::out);"

" ostrstream ();"

" ~ostrstream ();"

" char * str ();"

" int pcount ();"

};

" Descripci¢n de los m‚todos"

" ßßßßßßßßßßßßßßßßßßßßßßßßßß"

"ÜÜÜÜÜÜÜÜ"

" pcount Funci¢n miembro"

"ßßßßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ ostrstream ³ Devuelve el n£mero de bytes almacenados actualmente en el ³"

"³ ³ buffer: ³"

"³ ³ char *pcount () ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"ÜÜÜÜÜ"

" str Funci¢n miembro"

"ßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ ostrstream ³ Devuelve y congela (freeze) el buffer: ³"

"³ strstream ³ char *str () ³"

"³ ³ Debes liberar el buffer si es din mico. ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ strstreambuf ³ Devuelve un puntero al buffer y lo congela (freeze): ³"

"³ ³ char *str () ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Ejemplo sobre la clase ostrstream."

"#include <iostream.h>"

"#include <strstream.h>"

"#include <stdlib.h>"

"#include <string.h>"

"inline void error (const char *nomclase)"

{

" cerr << "Error en clase " << nomclase;"

" exit (1);"

}

"void main (void)"

{

" const short tam = 100;"

" char buf1[tam], buf2[tam], buf3 [tam], buf4[tam];"

" strcpy (buf1, "Ejemplo de la clase ostrstream.");"

" strcpy (buf2, "Ejemplo de la clase ostrstream.");"

" strcpy (buf3, "Ejemplo de la clase ostrstream.");"

" strcpy (buf4, "Ejemplo de la clase ostrstream.");"

" ostrstream s1 (buf1, tam);"

" if (! s1)"

" error ("s1");"

" ostrstream s2 (buf2, tam, ios::app);"

" if (! s2)"

" error ("s2");"

" ostrstream s3 (buf3, strlen (buf3) + 2, ios::app);"

" if (! s3)"

" error ("s3");"

" ostrstream s4 (buf4, tam);"

" if (! s4)"

" error ("s4");"

" s1 << 'a' << "bc" << ends;"

" s2 << 'a' << "bc" << ends;"

" // s3 << 'a' << "bc" << ends; // no se a¤ade ni c (de "bc") ni 0 (de ends)"

" s4 << 'a' << "bc";"

" cout << buf1 << endl << buf2 << endl << buf4 << endl;"

}

"/*"

"SALIDA:"

"(r)"

"abc"

"Ejemplo de la clase ostrstream.abc"

"abcmplo de la clase ostrstream."

"¯"

"OBSERVACIONES SOBRE EL PROGRAMA:"

"1) Con la clase ostrstream se trabaja de una forma similar que con la"

"clase ofstream, con la diferencia de que ostrstream escribe en un string"

"y ofstream escribe en un fichero."

"2) El modo de operaci¢n (tercer par metro de constructor ostrstream) por"

"defecto es ios::out."

*/

CLASE strstream "

" ÜÜÜÜÜÜÜÜÜÜÜ"

" strstream Proporciona entrada y salida simult nea sobre un strstreambuf."

" ßßßßßßßßßßß"

" ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

" ³ strstreambase ÃÄÄ¿ ÛßßßßßßßßßßßÛ ÚÄÄÄÄÄÄÄÄÄÄÄ¿"

" ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵ ÃÄÄÄÛ strstream ÛÄÄÄ´ <ninguna> ³"

" ³ iostream ÃÄÄÙ ÛÜÜÜÜÜÜÜÜÜÜÜÛ ÀÄÄÄÄÄÄÄÄÄÄÄÙ"

" ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

"Declarada en: strstrea.h"

" Constructores"

" ßßßßßßßßßßßßß"

"Crea un strstream din mico:"

" strstream ()"

"Crea un strstream con un buffer de n bytes especificado:"

" strstream (char*, int n, int mode)"

" Si el modo es ios::app o ios::ate, el puntero de lectura/escritura"

" es posicionado en el car cter nul del string."

" Funciones miembros"

" ßßßßßßßßßßßßßßßßßß"

" str"

" Definici¢n"

" ßßßßßßßßßß"

"class strstream : public strstreambase, public iostream"

{

" public:"

" strstream ();"

" strstream (char *, int _sz, int _m);"

" ~strstream ();"

" char * str ();"

};

" Descripci¢n de los m‚todos"

" ßßßßßßßßßßßßßßßßßßßßßßßßßß"

"ÜÜÜÜÜ"

" str Funci¢n miembro"

"ßßßßß"

"ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"

"³ ostrstream ³ Devuelve y congela (freeze) el buffer: ³"

"³ strstream ³ char *str () ³"

"³ ³ Debes liberar el buffer si es din mico. ³"

"ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"

"³ strstreambuf ³ Devuelve un puntero al buffer y lo congela (freeze): ³"

"³ ³ char *str () ³"

"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Ejemplo sobre la clase strstream."

"#include <iostream.h>"

"#include <strstream.h>"

"void main (void)"

{

" const short tam = 100;"

" char buf[tam];"

" strstream str (buf, tam, ios::in | ios::out);"

" const char sp = ' ';"

" str << 2 << sp << 3.3 << sp << 'x' << sp << "abc";"

" int i;"

" float f;"

" char c;"

" char s[10];"

" str >> i >> f >> c >> s;"

" cout << i << sp << f << sp << c << sp << s << endl;"

}

"/*"

"SALIDA:"

"(r)"

"2 3.3 x abc"

"¯"

"OBSERVACIONES SOBRE EL PROGRAMA:"

"1) Con la clase strstream se trabaja de una forma similar que con la clase"

"fstream, con la diferencia de que en strstream trabaja con un string y"

"fstream trabaja con un fichero."

"3) Con el modelo de operaci¢n (ios::in | ios::out) podemos escribir y leer"

"simult neamente sobre un mismo buffer."

*/

FICHERO strstream.h "

" ÜÜÜÜÜÜÜÜÜÜÜÜ"

" STRSTREA.H"

" ßßßßßßßßßßßß"

"Declara las clases de flujos de C++ para trabajar con arrays de bytes en"

"memoria."

" Incluye"

" ßßßßßßß"

" iostream.h"

" Clases"

" ßßßßßß"

" istrstream ostrstream strstream strstreambase"

" strstreambuf"

" Constantes, tipos de datos, y variables globales"

" ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß"

" _STRSTREAM_H_"

" Contenido (abreviado):"

" ßßßßßßßßßßßßßßßßßßßßßß"

"#ifndef __STRSTREAM_H"

"#define __STRSTREAM_H"

"#if !defined( __IOSTREAM_H )"

"#include <iostream.h>"

"#endif"

"class strstreambuf : public streambuf"

{

" // ..."

};

"class strstreambase : public virtual ios"

{

" // ..."

};

"class istrstream : public strstreambase, public istream"

{

" // ..."

};

"class ostrstream : public strstreambase, public ostream"

{

" // ..."

};

"class strstream : public strstreambase, public iostream"

{

" // ..."

};

"#endif"

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Ejemplo sobre las clases declaradas en el fichero strstream.h."

"#include <iostream.h> // para flujo cout"

"#include <strstream.h> // para clases istrstream y ostrstream"

"void main (void)"

{

" char *buffer_fuente = "Ejemplo de las clases istrstream y ostrstream.";"

" const int tam = 100;"

" char buffer_destino[tam];"

" istrstream flujo_fuente (buffer_fuente);"

" ostrstream flujo_destino (buffer_destino, tam);"

" char ch;"

" while (flujo_destino && flujo_fuente.get (ch))"

" flujo_destino.put (ch);"

" flujo_destino << ends;"

" cout << buffer_destino;"

}

"/*"

"SALIDA:"

"(r)"

"Ejemplo de las clases istrstream y ostrstream."

"¯"

"OBSERVACIONES SOBRE EL PROGRAMA:"

"1) Tal y como est el programa, el bucle while termina por la segunda"

"condici¢n: flujo_fuente.get (ch). Si tam fuera 10 en vez de 100, entonces"

"el bucle while se saldr¡a por la primera condici¢n: flujo_destino. En"

"este segundo caso, s¢lo se copiar n 10 caracteres de buffer_fuente, pero"

"hay que tener en cuenta que en este caso no se guarda el car cter 0 (con"

"ends) en buffer_destino pues no cabr¡a; esto significa que buffer_destino"

"no ser¡a un string terminado con el car cter nulo."

*/

CLASE bcd Y CLASE complex "

" Adem s de todos los ficheros de cabecera que acabamos de ver,"

" el C++ actual posee dos m s: ~bcd.h~ y ~complex.h~. En el primero"

" est declarada la clase ~bcd~ para que podamos trabajar con n£-"

" meros bcd (binary-code decimal) y en el segundo est declara-"

" da la clase ~complex~ para que podamos trabajar con n£meros com-"

" plejos."

" Aunque estas dos clases no tienen mucho que ver con la entra-"

" da y la salida, que es el objeto de esta lecci¢n, las vamos a"

" incluir en este lugar puesto que en esta lecci¢n es el £nico"

" lugar en el que hemos visto los ficheros de cabecera espec¡fi-"

" cos al C++, es decir, que no los posee el C ni pueden utilizar- "

" se en un programa de C."

FICHERO bcd.h "

" ÜÜÜÜÜÜÜ"

" BCD.H"

" ßßßßßßß"

"Declara la clase bcd de C++, m s los operadores sobrecargados para la clase"

"bcd y las funciones matem ticas bcd."

" Funciones"

" ßßßßßßßßß"

" abs acos asin atan cos cosh exp log log10"

" pow pow10 real sin sinh sqrt tan tanh"

" Constantes, tipos de datos, y variables globales"

" ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß"

" _BCD_H"

" _BcdMaxDecimals"

" bcdexpo (enum)"

" Constructores"

" ßßßßßßßßßßßßß"

" ÜÜÜÜÜ"

" ÝbcdÞ Convierte n£mero a decimal en c¢digo binario (bcd)."

" ßßßßß"

" Sintaxis:"

" bcd bcd (int x);"

" bcd bcd (double x);"

" bcd bcd (double x, int decimales);"

"Devuelve el equivalente BCD de un n£mero dado."

" Operadores sobrecargados"

" ßßßßßßßßßßßßßßßßßßßßßßßß"

" + -="

" - *="

" * /="

" / <="

" == >="

" != <"

" += >"

" Definici¢n (abreviada)"

" ßßßßßßßßßßßßßßßßßßßßßß"

"// ..."

"#ifndef __BCD_H"

"#define __BCD_H"

"#if !defined( __MATH_H )"

"#include <math.h>"

"#endif"

"#define _BcdMaxDecimals 5000"

"class bcd"

{

" public:"

" // Constructores"

" _Cdecl bcd();"

" _Cdecl bcd(int x);"

" _Cdecl bcd(unsigned int x);"

" _Cdecl bcd(long x);"

" _Cdecl bcd(unsigned long x);"

" _Cdecl bcd(double x, int decimals = _BcdMaxDecimals);"

" _Cdecl bcd(long double x, int decimals = _BcdMaxDecimals);"

" // Manipuladores bcd"

" friend long double _Cdecl real(bcd&); // Devuelve la parte real"

" // Funciones matem ticas del ANSI C sobrecargadas"

" friend bcd _Cdecl abs(bcd&);"

" friend bcd _Cdecl acos(bcd&);"

" friend bcd _Cdecl asin(bcd&);"

" friend bcd _Cdecl atan(bcd&);"

" friend bcd _Cdecl cos(bcd&);"

" friend bcd _Cdecl cosh(bcd&);"

" friend bcd _Cdecl exp(bcd&);"

" friend bcd _Cdecl log(bcd&);"

" friend bcd _Cdecl log10(bcd&);"

" friend bcd _Cdecl pow(bcd& base, bcd& expon);"

" friend bcd _Cdecl sin(bcd&);"

" friend bcd _Cdecl sinh(bcd&);"

" friend bcd _Cdecl sqrt(bcd&);"

" friend bcd _Cdecl tan(bcd&);"

" friend bcd _Cdecl tanh(bcd&);"

" // Funciones de operadores binarios"

" friend bcd _Cdecl operator+(bcd&, bcd&);"

" friend bcd _Cdecl operator+(long double, bcd&);"

" friend bcd _Cdecl operator+(bcd&, long double);"

" friend bcd _Cdecl operator-(bcd&, bcd&);"

" friend bcd _Cdecl operator-(long double, bcd&);"

" friend bcd _Cdecl operator-(bcd&, long double);"

" friend bcd _Cdecl operator*(bcd&, bcd&);"

" friend bcd _Cdecl operator*(bcd&, long double);"

" friend bcd _Cdecl operator*(long double, bcd&);"

" friend bcd _Cdecl operator/(bcd&, bcd&);"

" friend bcd _Cdecl operator/(bcd&, long double);"

" friend bcd _Cdecl operator/(long double, bcd&);"

" friend int _Cdecl operator==(bcd&, bcd&);"

" friend int _Cdecl operator!=(bcd&, bcd&);"

" friend int _Cdecl operator>=(bcd&, bcd&);"

" friend int _Cdecl operator<=(bcd&, bcd&);"

" friend int _Cdecl operator>(bcd&, bcd&);"

" friend int _Cdecl operator<(bcd&, bcd&);"

" bcd& _Cdecl operator+=(bcd&);"

" bcd& _Cdecl operator+=(long double);"

" bcd& _Cdecl operator-=(bcd&);"

" bcd& _Cdecl operator-=(long double);"

" bcd& _Cdecl operator*=(bcd&);"

" bcd& _Cdecl operator*=(long double);"

" bcd& _Cdecl operator/=(bcd&);"

" bcd& _Cdecl operator/=(long double);"

" bcd _Cdecl operator+();"

" bcd _Cdecl operator-();"

" // Implementaci¢n"

" private:"

" // ..."

};

"// ..."

"enum bcdexpo"

{

" ExpoZero,"

" ExpoInf,"

" ExpoNan,"

};

"// ..."

"#endif // __BCD_H"

" Descripci¢n de los m‚todos"

" ßßßßßßßßßßßßßßßßßßßßßßßßßß"

"La sintaxis de las funciones matem ticas del ANSI C aplicadas a objetos"

"de la clase bcd es similar as¡ que no se van a describir aqu¡ pues ya se"

"explicaron en el tutor de C; lo £nica diferencia est en que donde aparece"

"el tipo double en la funci¢n correspondiente al ANSI C, aparace el tipo"

"bcd en la correspondiente funci¢n matem tica sobrecargada; por ejemplo,"

"el prototipo del ANSI C"

" double cos (double x);"

"se convierte en la funci¢n cos sobrecargada correspondiente a n£meros"

"complejos en"

" bcd cos (bcd z);"

"Con los operadores sobrecargados para los objetos complejos ocurre lo"

"mismo que las funciones matem ticas sobrecargadas para los objetos"

"complejos."

"Hay una funci¢n (m‚todo) nueva en la clase bcd que no tiene correspondencia"

"con el tipo double:"

" ÜÜÜÜÜÜ"

" ÝrealÞ Devuelve la parte real del n£mero bcd."

" ßßßßßß"

" Sintaxis:"

" bcd real (bcd x);"

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Ejemplo de la clase bcd."

"#include <iostream.h>"

"#include <bcd.h>"

"void main (void)"

{

" bcd b1 (2), b2 (3.3);"

" cout << "b1: " << b1 // imprime: (r)b1: 2¯"

" << endl"

" << "b2: " << b2 // imprime: (r)b3: 3.3¯"

" << endl"

" << "b1 + b2: " << b1 + b2 // imprime: (r)b1 + b2: 5.3¯"

" << endl"

" << "abs (b1 - b2): " << abs (b1 - b2) // imprime: (r)abs (b1 - b2): 1.3¯"

" << endl"

" << "(b1 = b2 - 1): " << (b1 = b2 - 1) // imprime: (r)(b1 = b2 - 1): 2.3¯"

" << endl"

" << "real (b2): " << real (b2) // imprime: (r)real (b2): 3.3¯"

" << endl;"

}

FICHERO complex.h "

" ÜÜÜÜÜÜÜÜÜÜÜ"

" COMPLEX.H"

" ßßßßßßßßßßß"

"Declara las funciones matem ticas complejas de C++."

" Incluye"

" ßßßßßßß"

" iostream.h math.h"

" Funciones"

" ßßßßßßßßß"

" abs acos arg asin atan conj cos cosh exp"

" imag log log10 norm polar pow pow10 real sin"

" sinh sqrt tan tanh"

" Constantes, tipos de datos, y variables globales"

" ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß"

" _COMPLEX_H"

" Constructores"

" ßßßßßßßßßßßßß"

" ÜÜÜÜÜÜÜÜÜ"

" ÝcomplexÞ Crea n£meros complejos."

" ßßßßßßßßß"

" Sintaxis:"

" complex complex (double real, double imag = 0);"

"Devuelve el n£mero complejo con las partes real e imaginaria dadas."

" Operadores sobrecargados"

" ßßßßßßßßßßßßßßßßßßßßßßßß"

" + +="

" - -="

" * *="

" / /="

" == !="

" << >>"

" Definici¢n (abreviada)"

" ßßßßßßßßßßßßßßßßßßßßßß"

"// ..."

"#if !defined( __COMPLEX_H )"

"#define _COMPLEX_H"

"#if !defined( __MATH_H )"

"#include <math.h>"

"#endif"

"class complex"

{

" public:"

" // Constructores"

" complex(double __re_val, double __im_val=0);"

" complex();"

" // Manipuladores de complex"

" friend double _Cdecl real(complex&); // la parte real"

" friend double _Cdecl imag(complex&); // la parte imaginaria"

" friend complex _Cdecl conj(complex&); // el complejo conjugado"

" friend double _Cdecl norm(complex&); // el cuadrado de la magnitud"

" friend double _Cdecl arg(complex&); // el ngulo en el plano"

" // Crea coordenadas polares de un objeto complex dado"

" friend complex _Cdecl polar(double __mag, double __angle=0);"

" // Funciones matem ticas del ANSI C sobrecargadas"

" friend double _Cdecl abs(complex&);"

" friend complex _Cdecl acos(complex&);"

" friend complex _Cdecl asin(complex&);"

" friend complex _Cdecl atan(complex&);"

" friend complex _Cdecl cos(complex&);"

" friend complex _Cdecl cosh(complex&);"

" friend complex _Cdecl exp(complex&);"

" friend complex _Cdecl log(complex&);"

" friend complex _Cdecl log10(complex&);"

" friend complex _Cdecl pow(complex& __base, double __expon);"

" friend complex _Cdecl pow(double __base, complex& __expon);"

" friend complex _Cdecl pow(complex& __base, complex& __expon);"

" friend complex _Cdecl sin(complex&);"

" friend complex _Cdecl sinh(complex&);"

" friend complex _Cdecl sqrt(complex&);"

" friend complex _Cdecl tan(complex&);"

" friend complex _Cdecl tanh(complex&);"

" // Funciones de operadores binarios"

" friend complex _Cdecl operator+(complex&, complex&);"

" friend complex _Cdecl operator+(double, complex&);"

" friend complex _Cdecl operator+(complex&, double);"

" friend complex _Cdecl operator-(complex&, complex&);"

" friend complex _Cdecl operator-(double, complex&);"

" friend complex _Cdecl operator-(complex&, double);"

" friend complex _Cdecl operator*(complex&, complex&);"

" friend complex _Cdecl operator*(complex&, double);"

" friend complex _Cdecl operator*(double, complex&);"

" friend complex _Cdecl operator/(complex&, complex&);"

" friend complex _Cdecl operator/(complex&, double);"

" friend complex _Cdecl operator/(double, complex&);"

" friend int _Cdecl operator==(complex&, complex&);"

" friend int _Cdecl operator!=(complex&, complex&);"

" complex& _Cdecl operator+=(complex&);"

" complex& _Cdecl operator+=(double);"

" complex& _Cdecl operator-=(complex&);"

" complex& _Cdecl operator-=(double);"

" complex& _Cdecl operator*=(complex&);"

" complex& _Cdecl operator*=(double);"

" complex& _Cdecl operator/=(complex&);"

" complex& _Cdecl operator/=(double);"

" complex _Cdecl operator+();"

" complex _Cdecl operator-();"

" // Implementaci¢n"

" private:"

" double re, im;"

};

"// Funciones inline de complex"

"// ..."

"#endif // __COMPLEX_H"

" Descripci¢n de los m‚todos"

" ßßßßßßßßßßßßßßßßßßßßßßßßßß"

"La sintaxis de las funciones matem ticas del ANSI C aplicadas a objetos"

"de la clase compleja es similar as¡ que no se van a describir aqu¡ pues"

"ya se explicaron en el tutor de C; lo £nica diferencia est en que donde"

"aparece double en la funci¢n correspondiente al ANSI C, aparace el tipo"

"complex en la correspondiente funci¢n matem tica sobrecargada; por ejemplo,"

"el prototipo del ANSI C"

" double cos (double x);"

"se convierte en la funci¢n cos sobrecargada correspondiente a n£meros"

"complejos en"

" complex cos (complex z);"

"Con los operadores sobrecargados para los objetos complejos ocurre lo"

"mismo que las funciones matem ticas sobrecargadas para los objetos"

"complejos."

"S¡ merece la pena explicar las nuevas funciones (m‚todos) aportados por"

"la clase complex: real(), imag(), conj(), norm(), arg() y polar():"

" ÜÜÜÜÜÜ"

" ÝrealÞ Devuelve la parte real de un n£mero complejo."

" ßßßßßß"

" Sintaxis:"

" double real (complex x);"

" ÜÜÜÜÜÜ"

" ÝimagÞ Devuelve la parte imaginaria de un n£mero complejo."

" ßßßßßß"

" Sintaxis:"

" double imag (complex x);"

"Los datos asociados a un n£mero complejo est n compuestos por dos n£meros"

"en coma flotante (double). La funci¢n imag() devuelve el que se considera"

"parte imaginaria de los dos."

" ÜÜÜÜÜÜ"

" ÝconjÞ Devuelve el complejo conjugado de un n£mero complejo."

" ßßßßßß"

" Sintaxis:"

" complex conj (complex z);"

"Devuelve el complejo conjugado del n£mero complejo z."

" ÜÜÜÜÜÜ"

" ÝnormÞ Devuelve el cuadrado del valor absoluto."

" ßßßßßß"

" Sintaxis:"

" double norm (complex x);"

"La norma puede desbordarse por encima (overflow) si la parte real o la"

"parte imaginaria son suficientemente grandes."

" ÜÜÜÜÜ"

" ÝargÞ Da el ngulo de un n£mero en el plano complejo."

" ßßßßß"

" Sintaxis:"

" double arg (complex z);"

"El eje real positivo tiene ngulo 0, y el eje imaginario positivo tiene"

" ngulo pi/2. Si z es 0, devuelve 0."

" ÜÜÜÜÜÜÜ"

" ÝpolarÞ Calcula el n£mero complejo con la magnitud y el ngulo dados."

" ßßßßßßß"

" Sintaxis:"

" complex polar (double mag, double angulo);"

"El ngulo por defecto es 0. Estas dos declaraciones son iguales:"

" polar (mag, angulo);"

" complex (mag * cos (angulo), mag * sin (angulo));"

" Programa ejemplo"

" ßßßßßßßßßßßßßßßß"

"// Ejemplo de la clase complex."

"#include <iostream.h>"

"#include <complex.h>"

"void main (void)"

{

" complex z1 (2.2), z2 (3, 4);"

" cout << "z1: " << z1; // imprime: (r)z1: (2.2, 0)¯"

" cout << endl;"

" cout << "z2: " << z2; // imprime: (r)z2: (3, 4)¯"

" cout << endl;"

" cout << "z1 + z2: " << z1 + z2; // imprime: (r)z1 + z2: (5.2, 4)¯"

" cout << endl;"

" cout << "abs (z1-z2): " << abs (z1-z2); // imprime: (r)abs (z1-z2): 4.079216¯"

" cout << endl;"

" cout << "(z1 = z2-1): " << (z1 = z2-1); // imprime: (r)(z1 = z2-1): (2, 4)¯"

" cout << endl;"

" cout << "real (z2): " << real (z2); // imprime: (r)real (z2): 3¯"

" cout << endl;"

" cout << "imag (z2): " << imag (z2); // imprime: (r)imag (z2): 4¯"

" cout << endl;"

" cout << "conj (z1): " << conj (z1); // imprime: (r)conj (z1): (2, -4)¯"

" cout << endl;"

}

f f f f i i i i n n a a a a l

f i n n n a a l

f f f i n n n a a a a l

f i n n n a a l

f i i i i n n a a l l l l

D E L A T E O R I A D E L L E N G U A J E

~ ~

~ ÛÛÛÛÛÛÛÛ ~

~ ÛÛ ÛÛ ÛÛ ~

~ ÛÛ ÛÛÛÛÛÛ ÛÛÛÛÛÛ ~

~ ÛÛ ÛÛ ÛÛ ~

~ ÛÛÛÛÛÛÛÛ ~

~ ~




Descargar
Enviado por:Francisco
Idioma: castellano
País: España

Te va a interesar