General Apendice1

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 36

aok.

qxd

26/11/99 13:51

Pgina 527

APNDICE A

C FRENTE A C++
CONTENIDO
A.1.
A.2.
A.3.
A.4.
A.5.
A.6.
A.7.
A.8.
A.9.
A.10.
A.11.

Limitaciones de C.
Mejora de caractersticas de C en C++.
El primer programa C++.
Nuevas palabras reservadas de C++.
Comentarios.
Declaraciones de variables.
El especificador de tipos const.
Especificador de tipo void.
Los tipos char.
Cadenas.
Conversin obligatoria de tipos (Casting).

C ha alcanzado una enorme popularidad en la dcada de los ochenta y se ha


convertido en uno de los lenguajes ms utilizado de la dcada de los noventa.
Sin embargo, C tiene defectos y limitaciones que lo hacen inadecuado para proyectos de programacin complejos. C++ es un intento de mejorar C ampliando
sus caractersticas para soportar nuevos conceptos de desarrollo software.
Este apndice se ha escrito pensando en gran medida en programadores de C que desean emigrar a C++. Para ello, el primer paso a dar es
explicar las diferencias entre la definicin actual ANSI de C y la definicin
ANSI/ISO C++ Standar. El siguiente paso consistir en examinar cmo se
utilizan las funciones en C++. Los restantes apartados describirn cmo se
disean y escriben programas en C++ y las razones por las cuales los programadores actuales piensan que C++ es una de las mejores herramientas en
el campo de la ingeniera del software.
Sin embargo, aunque C++ es un superconjunto de C, la compatibilidad
entre los dos lenguajes no es perfecta. Este apndice le muestra las reas de
incompatibilidad que es necesario tener presente en el diseo de cualquier
programa en lenguaje C y C++.

A.1.

LIMITACIONES DE C

C, pese a su enorme popularidad, tiene reconocidas diferentes limitaciones.


Algunas de ellas son:

A.12. El especificador de tipo volatile.


A.13. Estructuras, uniones y enumeraciones.
A.14. Funciones en C++.
A.15. Llamada a funciones C. Programas mixtos C/C++
A.16. El tipo referencia.
A.17. Sobrecarga.
A.18. Asignacin dinmica de memoria.
A.19. Organizacin de un programa C++.
RESUMEN.
EJERCICIOS.

1. No se pueden definir nuevos tipos. La facilidad typedef es esencialmente un mecanismo para especificar un sinnimo de un tipo
existente.
2. Las declaraciones de funciones no ayudan a la verificacin de tipos
en las llamadas a funciones. Las versiones K&R de C no especificaban nada sobre tipos de parmetros. En ANSI C se ha introducido
la declaracin de tipos de los parmetros, pero de modo opcional.
C++ exige de modo obligatorio los prototipos.
3. Cuando las funciones se compilan separadamente, no se realiza ninguna verificacin para asegurar que los tipos de argumentos corresponden a los tipos de parmetros. Si una funcin se compila separadamente, los compiladores C no verifican que esta funcin es
llamada consistentemente con respecto a su definicin.
4. No existen tipos de coma flotante de simple precisin. Todas las
variables de tipo float se convierten a double en expresiones o
cuando se pasan como argumentos. C++ soporta float como un
tipo distinto.

A.2.

MEJORA DE CARACTERSTICAS DE C EN C++

C++ incorpora nuevas caractersticas no encontradas en ANSI C. Las mejoras se pueden agrupar en tres categoras:

aok.qxd

26/11/99 13:51

528

Pgina 528

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

1. Caractersticas de C++ que potencian C.


2. Extensiones al sistema de tipos de datos que permite disponer tipos
definidos por el usuario ms robustos (fuertes).
3. Extensiones que incorporan propiedades OO.

TABLA A.1. Caractersticas que potencian C

Caractersticas

Propsito

Nuevo estilo de comentarios


Tipos referencia
Funciones en lnea

Proporcionan mejora en legibilidad de cdigo.


Permiten paso de parmetros por referencia.
Permite que las funciones se expandan en lnea;
similares a las ms macros, pero mayor eficacia de
cdigo.
Los operadores estndar de C pueden trabajar con
tipos definidos por el usuario, tal como un operador
que sume nmeros complejos, cadenas o matrices.
Permite especificar valores por omisin para
parmetros de funciones.
Permite que un grupo de funciones con nombres
similares realicen tareas diferentes cuando son invocadas.

Sobrecarga de operadores

Parmetros por omisin


Sobrecarga de funciones

TABLA A.2. Extensin (ampliacin) en los sistemas de tipos de datos

Caractersticas

Propsito

Prototipos de funciones

Proporcionan verificaciones de tipos


en las llamadas a funciones.
Simplifica la sintaxis de los tipos
definidos por el usuario.
Soporta asignacin dinmica de tipos
definidos por usuario hace la administracin dinmica de memoria ms
segura.
Captura errores de paso de parmetros
realizando verificacin de tipos en
tiempo de enlace.
Permite mayor flexibilidad en la entrada
y salida de tipos definidos por el usuario, soporta entrada/salida (E/S) orientada a objetos; permite especificar rutinas
para convertir de un tipo a otro.

Las etiquetas de struct, union y enum


son nombres de tipos
Operadores de asignacin de memoria

Enlazado con seguridad de tipos

Biblioteca de nuevos flujos

TABLA A.3. Extensiones orientadas a objetos

Extensiones
de tipos

Tipos definidos por el usuario


(struct, union, enum)
Orientadas
Prototipos de funciones
a objetos
Asignacin de memoria
(new, delete)
Enlace con seguridad de tipos
Biblioteca de flujos
Conversiones de tipos definidos
por el usuario
Clases control de acceso

Comentarios en una lnea


Funciones en lnea
Tipos de referencia
Sobrecarga de funciones
Sobrecarga de operadores
Parmetros por omisin

Clases derivadas
Funciones virtuales
Funciones amigas
Constructores
Destructores

Extensin

Propsito

Clases

Permite a las funciones y datos agruparse juntos, se utilizan para crear objetos.
Permite restringir el acceso a los datos y funciones de
una clase.
Clases que heredan propiedades de las clases base existentes y permite la reutilizacin y extensin de clases.
Permite acceso selectivo a miembros de acceso restringido de una clase.
Mecanismo que facilita el polimorfismo y que determina la funcin a llamar en tiempo de ejecucin, no en
tiempo de compilacin.
Crean las funciones definidas por el usuario para la inicializacin de objetos.
Se llaman automticamente para limpiar memoria cuando los objetos se tienen que borrar o liberar.

Control de acceso
Clases derivadas
Funciones amigas
Funciones virtuales

Constructores
Potencian C

Destructores
FIGURA A.1. Caractersticas de C++ frente a C.

aok.qxd

26/11/99 13:51

Pgina 529

C FRENTE A C++

529

A.3. EL PRIMER PROGRAMA C++

A.3.1.

Un primer programa que visualiza las lneas siguientes:

Con el objeto de ver la elegancia y facilidad de escritura de C++ respecto a


C, supongamos un sencillo programa que teclee un nmero entero n, despus visualiza la lista de enteros comprendidos entre 1 y n, y calcula el total
de nmeros visualizados.
Comparando el programa EJEMPL02. CPP con EJEMPL01.C se observan las siguientes diferencias:

Hola programadores de C.
Bienvenidos al mundo de C++

se escribe as:
//archivo hola.cpp
#include <iostream.h>
int main ()
{
cout << Hola programadores de C. >> endl;
cout << Bienvenidos al mundo de C++ >> endl;
}

Los programadores de C reconocen la sentencia #include y la definicin de la funcin main (), pero no estn familiarizados con el archivo de
cabecera iostream.h.
Las facilidades de entrada y salida que se utilizan en programas C tambin se pueden utilizar en programas C++. Sin embargo, para mostrar las
nuevas propiedades de C++, el programa anterior utiliza las facilidades de
entrada/salida por flujos:
cout << Hola programadores de C. >> endl;
cout (como stdout) es el flujo de salida estndar. El operador << es
el flujo de salida. << escribe su operando derecho al flujo de salida especificado por su operando y devuelve el operando izquierdo como resultado.
La sentencia anterior se puede escribir tambin en dos partes:
cout << Hola programadores de C. << endl;
cout << endl;

La llamada a cout con el manipulador end1 produce un carcter de nueva


lnea. La representacin estndar del carcter nueva lnea tambin se admite.

Comparacin de programas C y C++

En lugar de incluir el archivo de cabecera <stdio.h>, el programa


C++ llama a <iostream.h>. A continuacin, las entradas/salidas no
utilizan las funciones printf() o scanf(), sino los flujos especializados de C++, gracias a los objetos cout y cin y a los operadores << y >> .
La declaracin de la funcin leer_num() no tiene necesidad del calificador void para indicar que no toma ningn argumento; es similar
a la funcin main().
En lugar de declarar todas las variables al principio de cada funcin,
las variables se declaran justo antes de su primera utilizacin (en
especial la variable i, que sirve de contador en el bucle for de la funcin main()).
Una nueva sintaxis para comentarios: se inician por una doble barra
inclinada, //, y se terminan al final de la lnea actual (no necesitan
carcter de cierre como en C ANSI).
/* archivo EJEMPL01.C*/
#include <stdio.h>
int leer_num(void)
{
int n;
/* lectura del nmero */
printf (Escribir un nmero:);
scanf (%d, &n);
return n;
}

cout << Hola programadores de C \n;

El programa C++ se puede escribir utilizando las facilidades de entrada/salida:


#include <stdio.h>
int main()
{
cout << Hola programadores de C. << endl;
cout << Bienvenidos al mundo de C++ << endl;
}

void main (void)


{
int i, fin;
long total = 0;
fin = leer_num();
for (i = 1; i <= fin; i++)
{
total += i;
printf (i = %d, i);

aok.qxd

26/11/99 13:51

530

Pgina 530

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

Algunos compiladores, ya obsoletos, de C++ incorporan otras palabras


reservadas, tales como overload. Por el contrario, otras palabras tales
como catch, template y throw, no son de amplio uso todava y existen
compiladores de C++ que todava no las soportan. La palabra reservada
template se utilizar para permitir la definicin de familias de tipos o funciones. Los mecanismos para el tratamiento de excepciones utilizarn las
palabras reservadas catch y throw.

printf (***total = %ld\n, total);


{
printf (***total = %ld\n, total)
}
// archivo EJEMPL02.CPP
#include <iostream.h>
int leer_num()
{
cout << Escribir un nmero=;
int n;
cin >> n;
return n;
}

El nuevo estndar ANSI C++

void main ()
{
int fin = leer_num();
long total =0;
for (int i = 1; i <= fin; i++)
{
total += i;
cout << i= << i << total= << total << endl;
{
cout << *** total= << total << endl;
}

Tras estas consideraciones y comparaciones generales, pasemos a describir detalladamente todas las caractersticas y propiedades que mejoran C
mediante C++, el lenguaje diseado por Stroustrup.

A.4.

NUEVAS PALABRAS RESERVADAS DE C++

Para soportar programacin orientada a objetos, C++ introduce quince nuevas palabras reservadas que se aaden a las palabras reservadas de ANSI C.
Si desea compilar un programa en C con un compilador C++ se deben evitar el uso de las palabras reservadas especficas de C++. Estas nuevas palabras reservadas son:
asm

catch

class

delete

friend

inline

new

operator

private

protected

public

template

this

throw

try

virtual

volatile

El comit ANSI ha aadido nuevas palabras reservadas al estndar de C++.


Estas palabras tratan de soportar los tipos adicionales bool (tipo lgico) y
wchar_t, as como nuevas caractersticas, tales como espaciosDeNombres
(namespace) e identificacin de tipos en tiempo de ejecucin.
TABLA A.4. Palabras reservadas aadidas recientemente
bool
const_cast
dynamic_cast

A.5.

false
mutable
namespace

reinterpret_cast
static_cast
true

typeid
using
wchart_t

COMENTARIOS

C++ soporta dos tipos de comentarios. El mtodo tradicional, /* comentario*/ es ya conocido por los programadores de C. El compilador ignora todo
lo que viene despus de un smbolo /* y hasta que se encuentra con /*. Por
ejemplo, en este programa:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:

/*
programa prueba
finalidad: visualizar enteros de 0 a 9
*/
#include <iostream.h>
int main()
{
int i;
for (i = 0;i < 10;i++)
cout << i << \n;
}

// bucle con 10 iteraciones


// visualizar enteros

aok.qxd

26/11/99 13:51

Pgina 531

C FRENTE A C++

531

Las lneas 1 a 4 se ignoran totalmente por el compilador.


El segundo formato de comentarios es especfico de C++. El comentario comienza con el smbolo // y termina con el final de la lnea actual. Esta
nueva forma de comentario, denominada comentario de una lnea, es adecuada para comentarios breves y un medio fcil de comentar. El programa
anterior muestra ambos tipos de comentarios.
Se puede utilizar una barra inclinada \ al final de un comentario de una
sola lnea para escapar (continuar) a una nueva lnea, aunque esta accin, no
es muy buena prctica.

//comentario empieza aqu\


y contina aqu.

existe ms que durante el tiempo de ejecutar su bloque (sentencias entre llaves). Eso permite declarar dos variables diferentes de igual nombre en dos
bloques diferentes y separados como en el ejemplo siguiente:

Al igual que en C, no se pueden anidar comentarios estilo tradicional


/*comentario, aunque algunos compiladores s lo permiten. Sin embargo,
una vez que el compilador ve //, ignora todo hasta el final de la lnea.
//i = 1;

/* comentario tradicional*/

El estilo de comentarios /*...*/ se utiliza para instrucciones de bloques


grandes, donde los comentarios exceden la longitud de una lnea.
El estilo // se utiliza para comentarios de una lnea.

A.6.

DECLARACIONES DE VARIABLES

Una de las diferencias ms evidentes entre los dos lenguajes reside en la


declaracin de variables. C es muy restrictivo. Todas las declaraciones en C
deben ocurrir al principio de un bloque funcin o un bloque creado por un
par de llaves ({) y (}). Se deben declarar todas las variables, no slo antes
de que se utilicen, sino antes de cualquier sentencia ejecutable. En C + + las
variables se pueden declarar en cualquier parte del cdigo fuente. El
siguiente ejemplo es correcto en C + + pero no en C:
void f()
{
double ds = sin(5.0);
ds *= ds;
double dc = cos(5.O);
dc *= dc;
}

Se puede obtener el mismo efecto en C introduciendo bloques extra


anidados:

double ds = sin(5.0);
ds *= ds;
{
double dc = cos(1.0);
dc *= dc;
}
}

Las variables se pueden declarar en bloques internos, funciones o bucles


for. As, la declaracin en bloques internos significa que la variable no

if (test)
{
int i = 0;
// ...
}
else
{
long i = 5;
}

La posibilidad de declarar las variables en cualquier punto de un programa permite situarlas prximas a las sentencias donde se utilizan. El
siguiente programa muestra esta caracterstica:
#include <stdio.h>
int main()
{
int i;
for (i = 0; i < l00; ++i)
cout << i << /n;
double j;
for (i = 1.79154; j < 22..58131; j + = .001)
cout << y << endl;
}

El siguiente programa es una variante del anterior, donde se muestra


cmo las declaraciones se pueden construir legalmente en cualquier punto
del programa.
#include <iostream.h>
int main()
{

aok.qxd

26/11/99 13:51

532

Pgina 532

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

Un ejemplo de declaracin de variables se muestra a continuacin:

for (int i = 0; i < 99; ++ i)


cout << i << endl;
for (double j = 1.79154; j < 22.5813; j + = 0.001)
cout << i >> endl;
}

Todas las declaraciones en C se deben realizar antes de que se ejecute


cualquier sentencia.
Las declaraciones en C++ se pueden declarar en cualquier parte de un
prrograma antes de su uso

//estilo C
double media (double num[100], int tamanyo)
{
int bucle;
double total = 0;
for(bucle = 0; bucle < tamanyo; bucle++)
total+= num[bucle];
return total/tamanyo;
}

A.6.1.

En C++, la funcin anterior media se escribe as:

Declaracin de variables en un bucle for

En C + +, una variable puede declararse en el interior de un bucle for.

double media (double num[100], int tamanyo)


{
double total = 0;

/* declaracin en C */
int main ()
{
int j;
cout << comienzo << endl;
for(j = 0; j < 100; j++)
{
int a;
cout << bucle << endl;
...
a = j;
...
}
}
//declaracin en C++
int main ()
cout << comienzo << endl;
...
for(int j = 0; j < 100; j++)
{
cout << bucle \ n;
...
int a = j;
...
}
}

for(int bucle 0; bucle < tamanyo; bucle++)


total += num[bucle];
return total/tamanyo;
}

C++ permite que las declaraciones se siten lo ms prximas posible al


lugar de su uso real.
El estilo actual C++ de declarar e inicializar simultneamente un contador del bucle ha de tener presente que el mbito de la variable se extiende
desde su definicin hasta el final del bloque que contiene el bucle for en el
caso de la funcin main hasta el final. Sin embargo, no es legal inicializar
las variables en otras estructuras de control, tales como:
while (int a == 5)
{
//... cuerpo del bucle
}
//...
if (int b == 6)
{
//... tratamiento del caso b == 6
}

Estas sentencias son realmente intiles, ya que no es racional declarar


una variable y comparar inmediatamente su valor.

aok.qxd

26/11/99 13:51

Pgina 533

C FRENTE A C++

A.6.2.

Declaraciones externas

Al contrario que C ANSI, C++ requiere que la palabra reservada extern sea
utilizada para especificar una declaracin externa especfica. En ausencia de
la palabra reservada extern, una sentencia de declaracin se considera
como una definicin. Obsrvese que una definicin de variable es equivalente a una declaracin de variable, excepto que la definicin asigna almacenamiento para la variable, mientras que una declaracin no lo hace. En
consecuencia, si
int a;

aparece fuera del cuerpo de una funcin, C ANSI lo considerar una declaracin mientras que C++ lo considerar una definicin. C++ indicar un
archivo que contiene dos declaraciones globales

533

}
ejemplo2 ()
{
int x, y;
{
int p;
}
}

// local a ejemplo2
// p, local a bloque interno

En contraste con una variable local, un mbito de una variable archivo


se declara fuera de cualquier clase o funcin. La disponibilidad de esta clase
de datos se extiende desde el punto de la declaracin al final del archivo
fuente en que se declara, con independencia del nmero de bloques implicados. Por ejemplo, el cdigo siguiente:
int cuenta;

int a;
int a;

ejemplo1()
{
...
}

como un error.
En C, las sentencias anteriores se tratan como declaraciones equivalentes a:

ejemplo2()
{
...
}

extern int a;
extern int a;

define una variable entera cuenta, a la que se puede acceder tanto en ejemplol como en ejemplo2. Esta variable, como seguramente conoce el lector,

Slo la presencia de un valor inicial para una variable externa convierte una declaracin externa en C en una definicin; por ejemplo:
int a == 0;

es una definicin externa.

A.6.3.

El mbito de una variable

Las reglas de mbito de C++ y C son similares. Existen tres mbitos posibles para una variable u otro dato: local, file y class. Examinaremos
los mbitos local y file.
Una variable local se utiliza exclusivamente dentro de un bloque. Los
bloques se definen por una pareja de llaves:
ejemplo1 ()
{
int x, y;
...

// locales a la funcin ejemplo1()

se denomina variable global. Considere el siguiente fragmento de cdigo:


int cuenta = 5;
ejemplo()
{
int cuenta = 10;
...
}

Se produce un conflicto entre dos objetos con el mismo mbito. Qu


versin de cuenta utiliza la funcin? La respuesta es sencilla, ya que la
regla es igual en C que en C + +. El nombre ms local tiene prioridad. Aqu
el valor de cuenta declarado en el interior de la funcin es el que se utiliza
en la funcin. Mediante el operador de resolucin de mbito (::) se cambia
la referencia de un nombre de una variable local y se puede acceder a un elemento oculto al mbito actual. Por ejemplo, la siguiente funcin ilustra el
uso de este operador:
#include <iostream.h>
int cuenta = 5;
main()
{

aok.qxd

26/11/99 13:51

534

Pgina 534

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

int cuenta = 10;


cout << cuenta interna = <<cuenta << \n;
cout << cuenta externa = <<::cuenta << \n;
}

El operador :: permite no utilizar la variable local, sino que se referencia a una variable de igual nombre fuera de su mbito. El programa anterior
visualizar:
cuenta interna = 10
cuenta externa = 5

El operador :: permite acceder a una variable global:


Estilo C
char *mensaje =Global;
...
void func()
{
char *mensaje = Local;
cout << mensaje;
//visualiza Local
}

Estilo C++
char *mensaje = Global;
...
void func()
{
char *mensaje = Local;
cout << mensaje;
//visualiza Local
cout << ::mensaje;
//visualiza Global
}

El operador de mbito se utilizar tambin en la definicin de las funciones (mtodos) de una clase para declarar la clase que pertenece a un
mtodo dado. El operador de mbito se puede utilizar para diferenciar entre
miembros de la clase base con nombres idnticos.

A.7.

EL ESPECIFICADOR DE TIPOS const

La clase de almacenamiento const, aunque oficialmente pertenece tambin


a ANSI C, no se utiliza con frecuencia entre los programadores en C, pero
s es muy usual en C++. const transforma una variable en una constante
simblica, es decir, su valor no se puede modificar. Dado que no se puede
asignar, una constante con nombre (tal como la define Stroustrup) debe ser
utilizada:

const
const
const
const

longlista;
// correcto en ANSI C, no en C++
int longlista = 12000;
int m[] = {1,2,3,4,59};
char mensaje [] = Preparado;// array de caracteres

La declaracin de const asegura que su valor no se modificar dentro


de su mbito:
longlista = 500; //error, no se puede modificar la constante
longlista++;
//error

El uso ms comn de const en C es sustituir a las constantes literales


#define; en C++ es tambin uno de sus usos ms importantes. As, en
lugar de escribir:
#define EOF -1
#define longmax 128
#define pi 3.14159

se debe escribir:
const EOF = -1;
const longmax = 128;
const pi = 3.14159;

Los nombres declarados con #define no tienen tipo, sin embargo, los
nombres declarados con const tienen tipo.
El compilador C++ siempre conoce el valor de una constante entera. El
siguiente fragmento de cdigo en C++ es aceptable, pero producir un error
en ANSI C:
const int buflon = 512;
char bufer[buflon];

El especificador const se puede utilizar con punteros:


const char* PC = luis;
PC[3] = 'a';
PC = mn1p;

//puntero a constante
//error
//correcto

Para declarar un puntero, en lugar del objeto apuntado, se utiliza una


constante const. Por ejemplo:
char *const cp = asdf;
cp[3] = 'a';
cp = ghjk;

//puntero constante a cadena


//conforme
//error el puntero es constante

aok.qxd

26/11/99 13:51

Pgina 535

C FRENTE A C++

Para hacer ambos objetos constantes deben ser declarados const. Por
ejemplo:

El ANSI C no evala las expresiones compuestas de variables const


ms que durante la ejecucin del programa; una variable const no
puede, pues, servir para dimensionar una tabla en ANSI C, como en
la sentencia:

const char *const cpc = asdf; //puntero const a const


cpc[3]= 'a';
//error
cpc = ghjk;
//error

const int LONGITUD = 100;


char tab1 [LONGITUD]; // error en ANSI C, legal en C++

Por el contrario, C++ evala las expresiones que contiene const


durante la compilacin, lo que permite utilizar estas expresiones exactamente como las constantes simblicas declaradas por #define.
Por defecto, una variable const de ANSI C es exportada hacia el editor de enlaces, lo que impide situar la definicin de una constante en
un archivo de cabecera: en efecto, si este archivo de cabecera es
incluido por diferentes mdulos del mismo programa, el editor de
enlaces registrar varias definiciones para la misma variable. En
C++, un identificador const posee una visibilidad que se limita al
mdulo en el cual est definido, como una variable de tipo static;
un identificador const puede ser definido en un archivo de cabecera, en el lugar en que se suelen utilizar las directivas #define.

El especificador const puede ser utilizado con punteros:


const char *ptrconst; //puntero a una cadena constante
char *const constptr; //puntero constante a una cadena

El especificador const se puede utilizar para proteger un valor de un


parmetro de una funcin:
void func(const int * miptr) {...}
*miptr = 10; // ERROR COMPILADOR, puntero a una constante

El modificador de tipo const se utiliza en C++ para proporcionar proteccin de slo lectura a variables y parmetros de una funcin. Las funciones miembro de una clase que no modifican los miembros dato a que
acceden se puede declarar const. Esto evita que estos miembros accedan a miembros dato no constantes. Tambin se utiliza para evitar que
parmetros pasados por referencia sean modificados.
void copias (const char*fuente, char*destino);

A.7.1.

Diferencias entre const de C++ y const de C

En ANSI C los objetos constante son realmente variables de slo lectura,


mientras que los objetos constante C++ son verdaderas constante. Por ejemplo, una variable entera constante ANSI C no se puede utilizar para especificar una dimensin de un array, ya que const sirve simplemente para crear
una variable cuyo valor no se puede modificar despus de su inicializacin.
En ANSI C una variable const se comporta como una variable clsica.
Un compilador ANSI C asigna siempre memoria para una variable
const, mientras que un compilador C++ ensaya almacenar el valor
correspondiente en su tabla de smbolos; la utilizacin de constantes
simblicas en C++ no consume sistemticamente memoria (al contrario que ANSI C).

535

La construccin const de C++ sustituye ventajosamente a las directivas


#define que servan para declarar constantes simblicas en ANSI C.
//archivo DEFCONTl.CPP, demo con #define
#include <iostream.h>
#define INICIO 20
#define FIN 60
#define LONGITUD FIN-INICIO
void main()
{
int tabl[LONGITUD];
int tab2[2 * LONGITUD];
int i;

// verdadero
// falso

for(i = 0; i < LONGITUD; i++)


tab1[i] = i;

// verdadero

for(i = 0; i < 2 * LONGITUD; i++)


tab2[i] = i;

// falso

cout << LONGITUD= << LONGITUD << endl;


cout << 2*LONGITUD = << 2 * LONGITUD < endl;
}

El resultado visualizado por el programa anterior es:

aok.qxd

26/11/99 13:51

536

Pgina 536

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

LONGITUD = 40
2*LONGITUD = 100

El mismo programa con la ayuda del calificador const en C++:


//archivo CONST1.CPP

pi, max y CD se declaran como variables constantes; s2, el segundo


parmetro de la funcin strcpy, declara como un puntero a un objeto constante; el valor de tal parmetro no puede modificar el cuerpo de la funcin.
Por ltimo, pn se declara como un puntero a una constante entera.
Algunas definiciones de arrays utilizando identificadores constantes
son:

#include <iostream.h>

const, int MAX = 100;

const int INICIO = 20;


const int FIN = 60;
const int LONGITUD = FIN - INICIO;

const int LONG_INEA = 255;


...
int db[MAX];

void main()
{
char tab1[LONGITUD];
char tab2[2*LONGITUD];
int i;

char linea[LONG_INEA+1];

for(i = 0; i < LONGITUD; i++)


tabl[i] i;
for(i = 0; i < 2 * LONGITUD; i++)
tab2[i] i;
cout << LONGITUD= << LONGITUD << endl;
cout << 2*LONGITUD= << 2*LONGITUD << endl;
}

Este programa visualiza ahora un resultado correcto:


LONGITUD = 40
2*LONGITUD = 80

Se debe indicar el tipo asociado a la constante (int en el ejemplo anterior) y obligatoriamente inicializar la constante durante su declaracin,
ya que es imposible modificar el valor de una constante fuera de su inicializacin
Algunos ejemplos de declaraciones variable const y parmetros const:
const float pi= 3.1416;
const int max = 24;
const complex CD = (0.0, 0,0);
char *strcpy(char *s1, const char *s2);
const int *pn;

# define PI 3.141519 // estilo antiguo C ANSI


const longitud = 100;
int buf [longitud];

// estilo c++
// no permitido en C ANSI

C++ requiere un inicializador.


C no requiere inicializar, por defecto se inicia a 0.

A.7.2.

Las variables voltiles

const indica al compilador que nunca cambia el valor del nombre. volatile indica al compilador que nunca conoce cundo cambiar el valor.

Se utiliza cuando se lee algn valor fuera del control del sistema, tal
como un registro en un soporte de hardware de comunicaciones. Una variable volatile se lee siempre que se requiere su valor, incluso si fue leda
justo en la lnea anterior. En el apartado A.12 ampliaremos este concepto.

A.8.

ESPECIFICADOR DE TIPO void

El tipo void es un tipo fundamental de datos que no tiene valores, representa


un valor nulo; void es una innovacin de C++ que se ha transportado a C
ANSI. Se utiliza fundamentalmente para especificar que una funcin no
devuelve un valor o como el tipo base para punteros a objetos de tipo desconocido.
void f();
void fr(int *)

// f no devuelve un valor
// fr toma un puntero a un argumento int y
// no devuelve un valor

aok.qxd

26/11/99 13:51

Pgina 537

C FRENTE A C++

Se utiliza tambin void para significar que la funcin no toma ningn


argumento. La funcin g no tiene un argumento y devuelve un int.
int g(void);

En C++, la sentencia anterior es equivalente a:

No se puede declarar un dato ordinario de tipo void:

A.8.1.

sizeof ('m') == 1;

sizeof('A') == 2
sizeof('A') == 1

// En C
// En C++

// no es correcto

En C todas las constantes char se almacenan como tipo int:

Punteros void

sizeof (1) == sizeof (int) sizeof (Q) == sizeof (int)

ANSI C permite que punteros de tipo void* sean asignados a cualquier otro puntero, as como cualquier puntero que sea asignado a un puntero de tipo void*.
C++ no permite asignacin de un tipo puntero void* a cualquier otro puntero
sin un molde explcito (cast). El siguiente ejemplo ilustra las diferencias:
void *p_void;
int i, *p_i;
p_void = &i;
p_i = p_void;
p_i = (int *)p_void;

En C++ char se trata como un solo byte.


sizeofe (1) == sizeof (Q) == sizeof (char)

Otro cambio en C++ es la existencia de tres tipos de caracteres distintos:


// vlido en C y C++
// vlido en C pero no en C++
// el molde lo hace vlido en C++

A una variable de tipo void* se le puede asignar cualquier valor de


puntero ( a cualquier tipo de datos). Asimismo, a una variable puntero
a un tipo especfico slo se puede asignar un void* y se realiza una
transformacin de tipo.

A.9.

ciencia de C es la promocin automtica de todos los tipos char a int cuando se pasan a funciones o se utilizan en expresiones.
C++ ha eliminado estas limitaciones. Las constantes carcter en C++
son verdaderas constantes caracteres; en C++

y un ejemplo comparativo es:

int g();

void v;

537

LOS TIPOS char

unsigned char
signed char
char

Todas ellas tienen un tamao igual a 1, pero no son idnticas en C++.

A.9.1.

Inicializacin de caracteres

En ANSI C se puede inicializar un array de tres caracteres con la siguiente


instruccin:
char nombre[3] = C++;

En C, todas las constantes caracteres (char) se almacenan como enteros


(int). As, la constante 'a' parece una constante carcter, pero en realidad es una constante entero. Esto significa que:
sizeof('m') == sizeof(int) == 2;

Es decir, en C clsico sizeof ('m') siempre produce el mismo resultado que sizeof (1) , que es 2 en implementaciones de 16 bts. Otra defi-

// vlido en ANSI C pero no en C++

Despus de la inicializacin, los elementos del array nombre [0], nombre[1] y nombre[2] se fijarn a C, + y +, respectivamente. Sin embargo, C++
no permite este tipo de inicializacin, ya que el array no tiene espacio para el
carcter de terminacin nulo. En C++ , si se necesita establecer el array nombre como se hace en C, tiene que rescribir la inicializacin del modo siguiente:
char nombre[3] = {'C','+','+'};

// vlido en C y C++

aok.qxd

26/11/99 13:51

538

Pgina 538

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

La siguiente inicializacin es vlida en C y C++ , pero establece un


array de 4 bytes con el ltimo byte establecido a un carcter nulo:
char nombre[] = C++;

int i = 0;
long l = (long)i;
long m = long (i);

//molde tradicional estilo C


//un nuevo estilo C++

// vlido en C y C++

Ejemplos comparativos de C y C++:

A.10.

CADENAS

Una constante cadena (tambin llamado un literal cadena o simplemente una


cadena) es una secuencia de caracteres escritas entre dobles comillas, como:
Cuntos nmeros
a

La declaracin y tratamiento de cadenas en C++ es similar a C, aunque


en C++ es posible concatenar literales cadena. As,
Hola Mundo

equivale a

double d = 3.9;
int i = 5,j;
j
j
d
d

=
=
=
=

i * (int)d;
i * int(d);
(double)i/ 7.0;
double(j)/ 7.0;

//estilo
//estilo
//estilo
//estilo

C ANSI
C++
C ANSI
C++

El segundo formato tipo (valor) suele ser ms fcil de leer. En C estndar, un puntero de tipo void* (es decir, un puntero hacia un objeto de tipo
indeterminado) se puede asignar a un puntero de cualquier tipo. En C++, la
conversin automtica de tipos o molde (casting) es obligatoria.
As, la funcin malloc devuelve un puntero de tipo void*, que se justifica debido a que malloc devuelve una direccin. En C estndar se puede
escribir:

Hola Mundo

y tambin

char *p;
p = malloc (100);

ABC DEF GHI


JKL

mientras que en C++ se debe escribir:

equivale a

char *p;
p = (char *) malloc (100);

ABCDEFGHIJKL

El mtodo antiguo de C con el carcter de escape \ tambin se puede


utilizar:
cout << Esta es una cadena que se considera\una sola lnea;

aunque el nuevo mtodo citado anteriormente es el ms idneo:

La notacin funcional no se puede utilizar para tipos que no tengan un


nombre simple, es decir, para los tipos puntero a tipos.
char *pc;
int i = 65, *pi = &i;
pc = (char *)pi;
pc = char *(pi);

//estilo C ANSI
//estilo C++, no correcto en este caso

cout << Esta es una cadena que se considera una sola lnea;

A.11.

CONVERSIN OBLIGATORIA DE TIPOS (Casting)

C++ soporta dos formatos diferentes de conversiones de tipos: estilo C,


segn la sintaxis (tipo) valor; estilo C++, con notacin funcional y sintaxis
tipo (valor). Algunos ejemplos de conversiones explcitas:

En este caso se puede utilizar la notacin funcional declarando un tipo


intermedio por typedef:
char* pc;
int i = 65, *pi = &i;
typedef char* ptr_car;

aok.qxd

26/11/99 13:51

Pgina 539

C FRENTE A C++

pc
pc

(char *)pi;
ptr_car(pi);

// estilo C ANSI
// estilo C++

539

{
while(!terminado)
...

//espera

A.12.

EL ESPECIFICADOR DE TIPO volatile

La palabra reservada volatile (voltil) se utiliza sintcticamente igual que


const, aunque en cierto sentido tiene significado opuesto. Las variables
voltiles se declaran con la palabra reservada volatile.

Variables volatile se pueden cambiar directamente por sofware del


sistema, hardware o por el programador. No se guardan en registros.

volatile int puerto75;

La declaracin de una variable voltil indica al compilador que el valor


de esa variable puede cambiar en cualquier momento por sucesos externos
al control del programa. En principio es posible que las variables voltiles
se puedan modificar no slo por el programador, sino tambin por hardware (puerto de E/S) o software del sistema (rutina de interrupcin). Otro
punto a considerar es que las variables no se guardan en registros, como es
el caso normal con variables ordinarias.
Un uso frecuente de volatile es leer algn valor fuera del control del
sistema, tal como un registro en algn dispositivo de hardware para comunicaciones. Es decir, en un programa de comunicacin de datos o en un sistema de alarma, algn componente hardware puede producir un cambio en
una variable, mientras que el programa nunca puede cambiar la variable.
Por ejemplo, el siguiente cdigo disea un bucle que acta sobre el
valor de una variable, esperando que se modifique por un manipulador de
interrupciones:
int terminado;
void espera;
{
while (!terminado)
;
}

//se fija a 1 por el manipulador de


//interrupciones

//espera

Este cdigo es posible que falle, o incluso peor, que falle dependiendo
de qu nivel de optimizacin se est seleccionando, ya que terminado no
est declarado voltil. Para permitir modificar datos, por ejemplo de modo
asncrono, es preciso declarar la variable terminado con el especificador
vo1atile, del siguiente modo:

A.13.

ESTRUCTURAS, UNIONES Y ENUMERACIONES

En C++, estructuras y uniones son realmente tipos de clases, ambas pueden


contener funciones y definiciones de datos. En lo relativo a su sintaxis y
funcionamiento difieren de la usual de C.
En C se pueden proporcionar nombres de los identificadores o etiquetas de una estructura, de modo que se puedan declarar estructuras con comodidad; el nombre del identificador no es un nombre verdadero de tipo en el
sentido de tipo int o similar. El nombre del identificador es simplemente un
mtodo para declarar copias adicionales de la estructura. En C++ los identificadores de la estructura han sido definidos como nombres reales de tipos.
struct punto {short x; short y;};

En C++ esta declaracin crea un nuevo tipo llamado punto, de modo


que a continuacin se pueden declarar variables (instancias) de tipo punto:
punto
punto
punto
struct

origen = {0,0};
caja[ 4]
*ptr_punto;
rect {punto origen; punto long;};

En C es comn utilizar typedef para hacer declaracin de estructuras


ms adecuadas. Esta tcnica tambin funciona en C++, aunque se necesita
slo para compatibilidad con el cdigo fuente C existente. Cuando el nombre de la etiqueta se omite en una declaracin struct typedef:
typedef struct {int a, b, d;} trio;

volatile int terminado;


...
void espera

//fija a 1 por el manipulador de


//interrupciones

el nombre de typedef, trio en el ejemplo anterior, se utiliza como nombre del tipo.

aok.qxd

26/11/99 13:51

540

Pgina 540

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

A.13.2.

En C el fragmento de cdigo
struc prueba {int a; float b;};
struct prueba p;

declara estructura con el nombre de etiqueta prueba y a continuacin


crea una instancia de prueba llamada p.

struc prueba {int a; float b;};


prueba p;

Los mismos convenios se aplican a uniones. Sin embargo, para mantener compatibilidad con C, C++ acepta an la sintaxis antigua.

Estructuras y uniones

En C++, las estructuras y uniones se han mejorado, dado que, como se ha


comentado, pueden contener datos y funciones. Sin embargo, se han realizado
dos cambios en C + + que pueden afectar a programas existentes.
Las etiquetas (tag) de estructuras y uniones se consideran nombres de
tipos, tal como si se hubiesen declarado con la palabra reservada typedef. El
siguiente cdigo muestra un fragmento de uso de una estructura en ANSI C.
struct cuadro {
int i;
float f;
};
struct cuadro nombre_i;

La estructura anterior declara una estructura con la etiqueta cuadro y crea


una instancia denominada nombre_i. En C++ las cosas son mucho ms simples, como se muestra en los ejemplos siguientes de una estructura y una unin:
struct cuadro
int i;
};
cuadro

nombre_i

Un tipo especial de unin se ha aadido a C++. Denominada unin annima, declara simplemente un conjunto de elementos que comparten la misma
direccin de memoria. Una unin annima no tiene nombre de etiqueta
identificador y se puede acceder a los elementos directamente por nombre.
Este es un ejemplo de una unin annima en C++:
union
{
int i;
float f;
};

En C++ esta declaracines ms simple:

A.13.1.

Uniones annimas

Tanto i como f comparten la misma posicin de memoria y espacio de


datos. Al contrario que las uniones con etiquetas identificadoras, a los valores de las uniones annimas se accede directamente. Este fragmento de
cdigo puede aparecer despus que se declare la unin annima anterior y
ser vlido:
i = 25
f = 4.5;

Esta propiedad de la unin ahorra memoria por comparticin de la


misma entre dos o ms campos de una estructura.

Comparacin de C y C++
//Ejemplo en C
union prueba {
int x;
float y;
double z;
},
main()
{
union prueba acceso;

typedef union {
int Entero1;
char *bufer;
}Ejemplo;

acceso.x = 21;
acceso.y = 434.484;
acceso.z = 7.745;
}

Ejemplo Ex1

// declara unin;

Los convenios dados para las estructuras se aplican a uniones.

El siguiente ejemplo se implementa en C++ y utiliza una unin annima para realizar la misma operacin.

aok.qxd

26/11/99 13:51

Pgina 541

C FRENTE A C++

int main()
{
union{
int x;
float;
double z;
};
x = 21;
y = 434.484; //el valor de y sobrescribe el valor de x
z = 7.745;
//el valor de z sobrescribe el valor de y
}

541

};
void test()
{
enum ventana w = saldo;
w--;
w = 3;
}

Las variables x, y, z, comparten la misma posicin de memoria y


espacio de datos.

Obsrvese que en C estn permitidas las operaciones aritmticas. El


programa anterior, sin embargo, no es legal en C++; si se han de realizar
operaciones aritmticas sobre valores de enumeracin en C + +, necesita utilizar operadores de conversin de tipos para sealar sus intenciones. El
equivalente en C++ de la funcin test:

A.13.3.

void test ()
{
ventana w = saldo;

Enumeraciones

Los tipos enumerados se tratan en C++ de modo ligeramente diferente a C.


En C++, el nombre de la etiqueta identificadora de una enumeracin es un
nombre de tipo. Esto permite utilizar un nombre de etiqueta de enum para
declarar una variable de enumeracin tal como se puede definir una estructura.
En C++, las enumeraciones slo tienen una operacin, asignacin. No
se pueden utilizar ninguno de los operadores aritmticos en enum y no se
puede, sin conversin automtica de tipos, asignar un valor entero a un tipo
enumerado. Estas reglas C++ son mucho ms estrictas que las que se pueden utilizar en C.
C define el tipo de enum como int. En C++, sin embargo, cada tipo de
enumeracin es el apropiado al mismo. Esto significa que C++ no permite
que un valor int sea convertido automticamente a un valor enum. Sin
embargo. un valor enumerado se puede utilizar en lugar de int.
El siguiente fragmento de cdigo C no ser correcto en C++:
enum Lugar {Primero,Segundo,Tercero};
Lugar Juan
int Vencedor
Lugar Pepe
Lugar Marca

=
=
=
=

Primero;
Juan;
1;
Lugar(1);

//vlido
//vlido
//error
//vlido con cast.

La sentencia de asignacin a Pepe es aceptable en C pero no en C++, ya


que 1 no es un valor definido por Lugar. El siguiente programa muestra un
uso tpico de enum en C:
enum ventana {
saldo,ingreso,pago

//no se necesita palabra reservada


//ventana, un nombre de tipo

((int &)w)--;
w = (ventana)3;
}

En C++ se puede declarar una variable de enumeracin sin utilizar la


palabra reservada enum. Esto se debe a que el nombre de una enumeracin
C++ es un nombre de tipo, tal como el nombre de una etiqueta, de una
estructura o una clase.
C++, al igual que C, permite especificar los valores numricos que se
asignan a las constantes de enumeracin. En nuestro ltimo ejemplo, los
valores por defecto son 0, 1 y 2, y se aplicarn a las constantes enumeradas
saldo, ingreso y pago, respectivamente. Esta declaracin muestra cmo
se especifican explcitamente los valores:
enum ventana{saldo = 0x10,ingreso = 0x20,pago = 0x40};

Obsrvese tambin que las constantes enumeradas no necesitan tener


valores distintos; a las constantes saldo e ingreso, por ejemplo, se les
puede asignar el valor 0x20 en el ejemplo anterior.
// declaraciones de nuevos tipos C clsico
enum dia
{lunes,martes,mircoles,jueves,viernes,sbado,domingo};
struct nodo {
int valor;
struct nodo* izquierda;
//estilo ANSI C
struct nodo* derecha;
//estilo C ANSI
};

aok.qxd

26/11/99 13:51

542

Pgina 542

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

enum dia d1, d2;


struct nodo n1, n2, n3;

//estilo C ANSI
//estilo C ANSI

declaraciones de variables
dia d1,d2;
nodo n1,n2,n3;

// declaraciones de funciones
void visualizar_dia(enum dia d);

//estilo C ANSI

// declaraciones de funciones
void visualizar_dia(dia d);
nodo* encontrar_valor(nodo* n);

struct nodo* encontrar-valor


(struct nodo* n);

//estilo C ANSI

Cada vez que se utilizan estos tipos de datos pierde legibilidad el cdigo.
// declaraciones de nuevos tipos C ANSI
enum dia
{lunes,martes,mircoles,jueves,viernes,sbado,domingo};
typedef enum dia t_dia;

//estilo C++
//estilo C++

Enumeraciones annimas

El lenguaje C++ soporta la creacin de enumeraciones annimas (enumeraciones sin etiquetas). Tal entidad se declara quitando la etiqueta o nombre de
la enumeracin. El siguiente segmento de cdigo es un ejemplo de una
declaracin de enumeracin annima.
enum { Rojo, Verde, Azul, Amarillo };

Utilizado de este modo, las constantes enumerables se pueden referenciar de igual modo que las constantes regulares, como se muestra a continuacin:

struct nodo {
int valor;
struct nodo* izquierda;
struct nodo* derecha;
{;

A.13.4.

//estilo C++

//estilo C ANSI
//estilo C ANSI

int pantalla = Rojo;


int borde = Verde;

typedef struct nodo t_nodo;

A.14.

// declaracin de variables
t_dia d1,d2;
t_nodo n1,n2,n3;

Al igual que en C, los programas C++ se componen de funciones. C++


introduce nuevas caractersticas para construir funciones ms eficientes,
seguras y legibles que sus equivalentes en C.

// declaracin de funciones
void visualizar_dia(t_dia d);
t_nodo* encontrar_valor(t_nodo* n);

En C++ los tipos de datos que se definen con la ayuda de struct y


enum se comportan como tipos incorporados.

enum dia
{lunes,martes,mircoles,jueves,viernes,sbado,domingo};
struct nodo {

};

A.14.1.

main()

C no define un formato especfico para la funcin main. As, es tpico escribir la definicin de la funcin principal:

// declaraciones de nuevos tipos

int valor;
nodo* izquierda;
nodo* derecha;

FUNCIONES EN C++

//estilo C++
//estilo C++

void main (void)


{
// cdigo programa principal
}

Sin embargo, main de C++ puede tomar una de las siguientes formas
(prototipos):

aok.qxd

26/11/99 13:51

Pgina 543

C FRENTE A C++

int main
int main(int argc,char *argv[])

En el segundo formato, argc representa el nmero de argumentos pasados al programa C++ desde la lnea de rdenes y argv[i] apunta al i-simo
argumento de la lnea de rdenes.
Al igual que en C, la terminacin de la funcin main termina el programa. La funcin main puede terminar con una llamada a la funcin exit
(con un argumento entero), alcanzando el final de su cuerpo, o ejecutando
la sentencia return. El argumento de la funcin exit es el valor devuelto
por el entorno. exit se llama normalmente con 1 para indicar fallo y con 0
si se indica xito. La terminacin de un programa por ejecucin de la sentencia return es equivalente a la terminacin del programa con la llamada
a exit.

#include <iostream.h>
int leer_nmero(1)
{
cout << Escribir un nmero
int n;
cin >> n;

//lectura de n

return n;
}

Puede existir ms de una sentencia return en una definicin de una


funcin, como en este ejemplo:
// RETURN.CPP
#include <iostream.h>
char func(const int i)
{
if(i == 0)
return 'a';
if(i == 1)
return 'g';
if(i == 5)
return 'z';
return 'c';
}
int main ()
{

cout << escribir un entero:;


int val;
cin >> val;
cout << func(val) << endl; //dara un mensaje advirtiendo
//que no devuelve nada
}

En C++ cualquier otro formato de cabecera para main generar un error.


La mayora de los compiladores C++ tambin proporciona un error o un mensaje de advertencia si no devuelve un valor main(). Esta accin se puede realizar con una sentencia return o una llamada a la funcin exit. Dado que
C++ fuerza a main a devolver un valor, es buena prctica de programacin
que la funcin main devuelva un valor.

A.14.2.

// archivo FUNC1.CPP

543

Prototipos de funciones

Los prototipos encontrados en C ANSI han sido tomados de C + +. Un prototipo de funcin es una declaracin que define el tipo devuelto y el tipo y
nmero de parmetros de una funcin. El compilador utiliza el prototipo de
la funcin para asegurar que al menos se proporciona el nmero correcto y
los tipos de argumentos cada vez que se utiliza la funcin. En C tradicional,
las funciones se declaran as:
int test();

En esta declaracin no se dice nada de los tipos de parmetros aceptados


por test. En C++ debe declararse test utilizando una sentencia similar a:
int test(char *cad, unsigned int long);

Esta declaracin significa que test es una funcin que devuelve un valor
entero (int)con dos parmetros, un puntero a carcter y un entero sin signo
(unsigned int). El compilador utiliza el prototipo para asegurar que los tipos
de los argumentos que se pasan en una llamada a una funcin son los mismos
que los tipos de los parmetros correspondientes. Esta propiedad se conoce
como verificacin estricta de tipos. Sin verificacin estricta de tipos es ms fcil
pasar valores ilegales a funciones. Una funcin sin prototipo permitir enviar
un argumento entero (int) a un parmetro puntero o utilizar un argumento
real (float) cuando espera un entero largo (long). Estas clases de errores
producen valores no vlidos para los parmetros de la funcin. Por otra parte,
cuando los tipos impropios se pasan a una funcin, el compilador no puede
restaurar la cantidad correcta del espacio de pila y su pila se puede romper.
Mientras que en ANSI C simplemante se utilizan prototipos, C++ los
requiere.

aok.qxd

26/11/99 13:51

544

Pgina 544

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

Los prototipos de C++ no siguen exactamente las mismas reglas que C.


En C++, este prototipo indica que aleatorio() es una funcin que no tiene
argumentos y que devuelve un tipo entero.
int aleatorio ();

En C, sin embargo, el mismo prototipo indica que aleatorio() es una


funcin que toma un conjunto de argumentos desconocidos y devuelve un
entero (int). Naturalmente, un prototipo de funcin de aleatorio() en
C++ mejor que el anterior es:

Cabeceras de funciones tipo prototipo


/*estilo C

//estilo c++

void widget (a, b);


int a,
double b;
{
//...
}

void widget (int a, double b)

El estilo de C++ es ms fcil comprender que el viejo estiloC.

int aleatorio(void);

En C++ no tenemos la facilidad de tener funciones tales como printf


y scanf(), que toman diferentes nmeros y tipos de argumentos. En C++
se utilizan puntos suspensivos para indicar qu nmeros y tipos variables de
argumentos son aceptables. El prototipo de C++ de printf es:
int printf(const char *, ... );
/* formato C */
int demo1(void);
int demo2();

// formato C++
int demo1();
int demo2(...);

Una funcin C++ que tiene una lista de parmetros abiertos requiere utilizar puntos suspensivos.
Recuerde que todas las funciones en C++ deben estar prototipadas. Esto
significa que cada funcin debe tener su lista de argumentos declarados, y
la definicin real de una funcin debe corresponder exactamente con su
prototipo en nmero y tipo de argumentos.
Los prototipos de funciones pueden significar un poco ms de trabajo cuando se escribe inicialmente un programa; sin embargo, los prototipos pueden tener un valor inapreciable en prevenir errores difciles de
encontrar. C++ fue diseado para prevenir muchos de los problemas del
programador imprudente que pasa tipos incorrectos a mtodos. Si realmente se necesita pasar un long como un int, se puede hacer utilizando
un molde (conversin forzosa de tipos). Algunos prototipos completos de
funciones:
int f1(void);
//devuelve un tipo int, no toma argumentos
void f2();
//como f4 () en c++ pero no en ANSI C
float f3(float, int, char, double);
// devuelve float
void f4(void); // no toma argumentos, devuelve nada

La Tabla A.4 resume las diferencias entre prototipos de funciones C y


C++.

TABLA A.4. Prototipos C y C++

Prototipo

Formato C

Formato C++

f (void);

int f (void)

void f (void);

funcin devuelve int

funcin no devuelve un valor

int f ();

int f () ;

no verificar argumentos de
funcin
int f(...);

no toma argumentos
int f(...);

no reconocida por la mayora no verifica argumentos de la


de los compiladores C
funcin

A.14.3.

Una declaracin tpica de funciones y prototipos

El lenguaje C++ es ms estricto que el ANSI C en los tipos de datos manipulados. En consecuencia, C++ impone declarar el nmero y tipo de argumentos que recibe una funcin, as como el tipo de valor devuelto. Estas
declaraciones son similares a los prototipos de funciones de la norma ANSI,
merced a los cuales el compilador puede verificar la coherencia de su cdigo fuente entre las declaraciones de las funciones y sus llamadas efectivas.
Sin embargo, mientras que la utilizacin de prototipos es opcional en ANSI
C, son obligatorios en C++ para que un programa sea aceptado por el compilador.

aok.qxd

26/11/99 13:51

Pgina 545

C FRENTE A C++

// Archivo PROTO1.CPP

cout << Teclear a b c


double a, b, c;
cin >> a >> b >> c;
discriminante(a, b, c);

#include <iostream.h>
void discriminante(a, b, c);
double a, b, c;
{
double d;
d = b*b-4*a*c;
visualizar(d);

545

//ERROR: antiguo estilo C


}

//ERROR: ningn prototipo


//antes de utilizar

La declaracin de un prototipo de funcin no debe necesariamente llevar los nombres de los argumentos formales de la funcin, sino nicamente
sus tipos. As, las dos declaraciones siguientes son equivalentes:

}
void visualizar(d)
double d;
{
cout << Discriminante = << d << endl;
}
void main ()
cout << Teclear a b c;
double a, b, c;
cin >> a >>b >> c;
discriminante(a, b, c);
{

// prototipo sin los nombres de los argumentos formales


void discriminante(double, double, double);

A.14.4.

//Archivo PROTO2.CPP
#include <iostream.h>
void visualizar(double d);

// prototipo con nombres de argumentos formales


void discriminante(double a, double b, double c);

//declaracin de prototipo

Funciones en lnea

En C se utilizan definiciones de macros para crear segmentos cortos de


cdigo. En C++ se incorporan funciones en lnea que son similares a
macros. Las funciones en lnea instruyen al compilador para sustituir el
cuerpo completo de la funcin en cada llamada a la funcin en lnea.
Cuando una lnea de la cabecera de la definicin de una funcin contiene la palabra inline, esa funcin no se compila como una parte independiente del cdigo llamado. En su lugar, la funcin se inserta siempre que una
llamada a esa funcin aparece en un programa. Por ejemplo, C++ compila
esta funcin como un cdigo en lnea.

//Estilos C++ y C ANSI


void discriminante(double a, double b, double c);
{
double d;
d = b*b-4*a*c;
visualizar(d);

//vlida

}
// Utilizacin de estilo C++ y C ANSI
void visualizar(double d)
{
cout << Discriminante =
}
void main ()

<< d << endl;

inline int suma(int a, int b)


{
return a + b;
}

Esta funcin no existe realmente como una funcin que se pueda llamar.
En su lugar, el compilador inserta el cdigo que realiza su tarea siempre que
aparece una llamada a suma en su programa. Los traductores de C crean
macros para las funciones en lnea e insertan esas macros en el programa C
resultante y apunta dnde es llamada la funcin. Un compilador C++ precompila la rutina e inserta las instrucciones precompiladas en las posiciones
apropiadas.
Existen algunas reglas para utilizar funciones en lnea. Las funciones en
lnea deben ser definidas antes de que puedan ser utilizadas. Esto se debe a
que el cdigo para la funcin en lnea debe ser precompilado antes que se

aok.qxd

26/11/99 13:51

546

Pgina 546

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

pueda insertar en el programa. Por consiguiente, el siguiente cdigo no se


compilar como se esperaba.
#include <stdio.h>
int suma(int a, int b);
int main()
{
int x = suma(1,2);
printf(%i\n,x);
}
inline int suma(int a, int b)
{
return a + b;
}

Cfront, el traductor estndar C ++ de AT&T, proporcionar un error que


indica se ha declarado y utilizado suma como una funcin real, pero se ha
definido como una funcin en lnea. Se deben definir siempre sus funciones
en lnea antes de ser referenciadas.
En esencia, la funcin en lnea aumenta el tamao del programa, ya que
se ha insertado el cdigo de la funcin en lugar de generar una llamada a la
funcin. Sin embargo, las funciones en lnea aumentan su eficiencia, ya que
incrementan su velocidad de ejecucin.
Dado que el cuerpo de la funcin en lnea se duplica siempre que se
llama a la funcin, se deben utilizar funciones en lnea slo cuando las funciones sean de tamao muy limitado (algunos bytes) y sean crticas en trminos de velocidad de ejecucin.
Un buen ejemplo de funciones en lnea aparece en la definicin de la
clase complex, que se incluye con la mayora de los compiladores C++ y
aparece en el archivo de cabecera <complex.h>.

class Rect
public:
Rect ();
Rect ();
int izquierda()
int derecha()
int cima()
int fondo()
private:
int x, y;
int anchura, altura;
};

A.14.5.

//Archivo : Mathlocal.h
//Prototipos (declaraciones de funciones)
inline int alos (int i);
inline int min (int v1, int v2);
int mcd (int v1, int v2);

Las funciones declaradas en lnea deben ser sencillas, con slo unas
pocas sentencias de programas. Deben ser llamadas slo un nmero limitado de veces y no deben ser recursivas.
Las funciones miembro declaradas con una definicin en la especificacin de la clase se consideran automticamente en lnea por el compilador:

return
return
return
return

x; }
x + anchura; }
y; }
y + altura;}

Ventajas sobre las macros

Las funciones en lnea son como macros del preprocesador, ya que el compilador sustituye el cuerpo de la funcin completo para cada llamada a una
funcin en lnea. Las funciones y las macros difieren esencialmente en
aspectos fundamentales:
Al contrario que a las macros, el compilador trata a las funciones en lnea
como funciones verdaderas.

Para ver cmo puede ser esto un factor importante, considrese el


siguiente ejemplo. Supongamos que se ha definido una macro llamada multiplicar de la forma siguiente:
#define multiplicar (x,y) (x*y)

si tuviera que utilizar esta macro:


x = multiplicar(4+1,6);

Ejemplos de funciones en lnea

{
{
{
{

//se pretende buscar 4+1 por 6

el preprocesador transformar el lado derecho de esta sentencia en el cdigo siguiente:


x= (4+1*6);

esta expresin se evala a 10 en lugar de proporcionar el resultado de (4 + 1)


por 6, que ser 30; naturalmente, una solucin a este problema es utilizar
parntesis. Sin embargo, considere lo que sucede cuando se define una funcin en lnea igual que una macro.
#include <stdio.h>
// definir funciones en lnea para multiplicar dos enteros

aok.qxd

26/11/99 13:51

Pgina 547

C FRENTE A C++

y analicemos diversas llamadas como ejemplos suplementarios:

inline int multiplicar(int x, int y)


{
return(x*y)
}
//versin sobrecargada que multiplica dos doubles
inline double multiplicar(double x, double y)
{
return(x*y);
}
main()
{
cout << Producto de 5 y 6= << multiplicar (4 + 1, 6) << endl;
cout << Producto de 3.1 y 10.0 = <<
multiplicar(3.0 + .1, 10.0) << endl;
}

La ejecucin produce la salida:

Las funciones en lnea evitan los errores de las macros, aumentan la


eficiencia y adems pueden ser sobrecargadas.

int defecto(int a = 5, int b = 6);

Por consiguiente:
defecto(5,6)
defecto(10,6)
defecto(10,20)

Los argumentos por omisin son los ltimos de la lista solamente.


Supongamos otro prototipo:
void g(int i=1, int j=2, int k=3);

grficos y se rellena con un color de fondo, que se puede fijar a valores


especficos por omisin para la posicin, tamao y color del fondo de la
ventana, como sigue:

ventana crear_ventana(int x=0, int y=0, int anchura=100,


int altura=50, int pixel=0);

ventana v;

En C++ existe otra mejora a las funciones en C, es que se pueden especificar los valores por omisin para los argumentos cuando se proporciona un
prototipo de una funcin. Es decir, determinados argumentos se pueden
omitir e inicializar a un valor por defecto u omisin, y a continuacin omitir el argumento real en la llamada. La sintaxis es la siguiente:

defecto()
es igual que
defecto(10)
es igual que
defecto(10,20) es igual que

Examinemos el ejemplo siguiente. Se define una funcin crear_ventana que establece una ventana (una regin rectangular) en una pantalla de

Con esta declaracin de la funcin crear_ventana se puede utilizar


cualquiera de las llamadas siguientes para crear nuevas ventanas:

Argumentos por omisin

una llamada a
una llamada a
una llamada a

g(5,6,7); es correcto (no se tienen en cuenta los valores


por omisin).
g(5,6);
es igualmente correcto, k toma automticamente
el valor 3.
g(5);
es correcto; j y k toman automticamente los
valores 2 y 3.
g();
es correcto; i, j, k toman respectivamente los
valores 1, 2 y 3.
g(,7,8);
error de compilacin.
g(,2);
error de compilacin.

//Una funcin con valores con argumentos por omisin


//Supongamos que ventana es un tipo definido por el usuario

producto de 5 y 6 = 30
producto de 3.1 y 10.0 = 31.000.000

A.14.6.

547

//La siguiente llamada equivale a


//crear_ventana(0,0,100,50,0)
v=crear_ventana();
//La siguiente llamada equivale a
//crear_ventana(100,0,100,50,0);
v=crear_ventana(100);
//La siguiente llamada equivale a
//crear_ventana(30,20,100,50,0);
v=crear_ventana(30,20);

Obsrvese que es imposible un valor especificado para el argumento


altura sin especificar los valores de x, y y anchura, ya que altura viene despus de ellos y el compilador slo puede corresponder argumentos por posicin. En otras palabras, el primer argumento que se especifica en una llamada a crear_ventana, siempre se corresponde con x, el segundo se

aok.qxd

26/11/99 13:51

548

Pgina 548

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

corresponde con y, etc. Por consiguiente, slo se pueden dejar los argumentos finales de la lista sin especificar, y adems se tienen que inicializar
todos de derecha a izquierda y consecutivamente:
//prototipo con error
void mackoy(int a=1, int b, int c=3, int d=4);
//prototipo vlido
void makena(int a, int b=2, int c=3, int d=4);

//C++ no permite inicializar arrays o estructuras local


//cuando se declaran
#include <iostream.h>
int a[10] = {81,78,45,78,91,45,76,87,54,99};
main()
{
void visualizar (const int a[], int n, int cuenta = l);

Veamos algunas llamadas a las funciones:

cout << Array modelo, uno por lnea. \n;


visualizar(a, 10);
cout << Array modelo, tres por lnea. \n;
visualizar(a, 10, 3);
return 0;

// conforme, args. para cada parmetro


makena(10,15,20,25);
// correcto, los dos ltimos parmetros toman el valor por omisin
makena(12,15);
// error, se saltan parmetros deben ser consecutivos
makena(3,10,,12);

Un ltimo ejemplo es el siguiente:


#include <stdio.h>
void f(int i, int j=2);

//se especifica valor por defecto

main()
{
f(4,5);
f(6);
}
void f(int i, int j)
{
cout << i: << i << y j: << j << endl;
}

}
void visualizar(const int a[], int n, int cuenta)
{
int i;
for (i = 1; i <= n; i++)
{
cout << a[i-11];
if (i%cuenta == 0 | | i == n)
cout << \n;
else if (i! = 0)
cout << ;
}
}

Comentario
Primer argumento (array a visualizar). Segundo argumento (nmero de elementos del array). Tercer argumento (nmero de elementos a visualizar en
cada lnea, por omisin = l).

La salida es:
i : 4 y j : 5
i : 6 y j : 2

El programa ARGOMI.CPP utiliza argumentos por omisin en las llamadas sucesivas a la funcin visualizar.
//Prueba de argumentos por omisin: ARGOMI.CPP
//Programa C++ que impone un array con diferentes elementos
//por lnea

A.14.7.

Funciones con un nmero variable


de parmetros (el parmetro...)

A veces es imposible listar el tipo y nmero de todos los argumentos que se


pueden pasar a una funcin. En estos casos, los puntos suspensivos (...) se
pueden especificar dentro del formato de la funcin.
En C++ se pueden introducir los puntos suspensivos en la declaracin
de parmetros formales de una funcin para indicar que la funcin se lla-

aok.qxd

26/11/99 13:51

Pgina 549

C FRENTE A C++

mar con diferentes conjuntos de argumentos en ocasiones diferentes. As,


la declaracin siguiente:
void func(int n, char car, ...);

indica que func se definir de tal forma que las llamadas deben tener al
menos dos argumentos, uno int y otro char, pero pueden tener tambin
cualquier nmero de argumentos adicionales. En C++ se puede omitir la
coma que precede a los puntos suspensivos.
Los puntos suspensivos pueden tomar cualquiera de los dos formatos en
las correspondientes llamadas:
func(lista_arg,...);
func(...);

/ /la coma es opcional

Esta caracterstica se encuentra en C, aunque normalmente no se piensa en ella. Sin embargo, un ejemplo claro de aplicacin de esta propiedad se
encuentra en la funcin printf(), que permite utilizar funciones con un
nmero variable de parmetros en C. C++ soporta tambin esta funcin,
cuyo prototipo recordemos es
printf(const char*...);

Las siguientes dos declaraciones no son equivalentes:


void f()
void f(...);

En el primer ejemplo, f() se declara como una funcin que no toma


argumentos; en la segunda, f(...) se declara como una funcin que puede
tomar cero o ms argumentos. Las llamadas

especifica una funcin que requiere dos argumentos enteros y un argumento double y un nmero adicional de argumentos que es desconocido en
tiempo de compilacin.
Un buen ejemplo de funciones con nmeros variables de argumentos es la
familia de funciones printf definidas en el archivo de cabecera <stdio.h>.
int fprintf(FILE *flujo, const char * formato, ...);
int printf(const char *formato, ...);
int sprintf(char *buffer, const char *formato, ...);

A.15.

LLAMADA A FUNCIONES C.
PROGRAMAS MIXTOS C/C++

La directiva extern c permite utilizar funciones compiladas con ANSI C.


Para indicar al compilador C++ que las funciones han sido compiladas,
segn el convenio ANSI C, se deben seguir las siguientes reglas:
1. Prototipo de funcin precedido por extern C:
extern C int sort(int a[], int n);

2. Las sentencias include se encierran en un bloque extern C:


extern C {
#include cmplx.h.
#include fourier.h

extern C {
typedef struct {
float r, i;
} complex;
complex
nuevocomplejo(float x, float y);
float
real(complex a);

f(valor);
f (xyz, a, b, c);

549

float
float

imag (comp1ex a);


}

son invocaciones legales slo de la segunda declaracin. La llamada


3. Especificar varias funciones con el modificador C.
f();

es una invocacin legal de ambas funciones.


Un uso tpico de la sintaxis puntos suspensivos implica una declaracin
de funciones en la que un conjunto de parmetros est seguida por el especificador de parmetros variables. Por ejemplo,

extern C {
char *memcpy(char *t, char *s);
int strlen(char *t);
}

La mayora de los compiladores C++ del mercado disponen de archivos


#include concebidos para poder ser utilizados indistintamente a partir de

int ejemplo(int, int, double...)

programas en lenguaje C y C++.

aok.qxd

26/11/99 13:51

550

Pgina 550

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

Comprobacin: vase archivo studio.h


estn construidos segn el modelo:

en \BORLAND\INCLUDE;

#ifdef _cplusplus
extern C {
#endif
void _Cdecl...
...
#ifdef _cplusplus
}
#endif

A.16.

EL TIPO REFERENCIA

En C, cuando se llama a una funcin con argumentos, los valores de los argumentos se copian en una rea especial de memoria conocida como la pila. La
funcin utiliza estas copias para su operacin. Este efecto se denomina llamada por valor. Para ver este efecto, consideremos el siguiente cdigo:
void dosveces(int a)
{
a *= 2;
}
...
int x = 5;

...
int x= 5;
// llamada a dosveces con la direccin de x como argumentos
dosveces(&x); printf(x=%d\n,x);

Esta vez el programa visualiza 10 como resultado. Por consiguiente, se


pueden pasar punteros para modificar variables a travs de una llamada a
funcin, pero la sintaxis es poco clara. En la funcin se tiene que desreferenciar el argumento utilizando el operador *.
C++ ha aadido un tipo de dato referencia que proporciona un medio de
pasar argumentos por referencia introduciendo el concepto de una referencia, que en esencia consiste en definir un alias o nombre alternativo para
cualquier instancia de datos. La sintaxis es aadir un ampersand (&) al
nombre del tipo de dato. En una declaracin se utiliza el ampersand para
especificar el tipo de dato referencia, de igual forma que el asterisco se utiliza para declarar un puntero:
double d = 0;
double &dr = d;
double *dp;
dr += 5.0;
dp = &dr;
int i = 5;
int *P-i = &i;
int &r_i = i;

//dr es una referencia a d


//dp es un puntero a double
//sumar 5.0 a dr
//apunta dp a dr

//un puntero a int inicializando para


//apuntar a i
//una referencia a la variable int i

// llamada a la funcin dosveces


dosveces (x) ;
printf(x=%d\n,x);

De hecho, se puede utilizar r_i en cualquier parte que utilice i o *p_i.


As, se escribe:
r_i + = 10;

Este programa imprime 5 como valor de x, no 10, pese a que la funcin


dosveces multiplica su argumento por 2. Esto se debe a que la funcin
dosveces recibe una copia de x y cualquier cambio que haga a esa copia
se pierde al retornar desde la funcin.
En C, el nico mtodo para cambiar el valor de la variable a travs de
una funcin es pasar explcitamente la direccin de la variable a la funcin.
As por ejemplo, para doblar el valor de una variable, se puede escribir la
funcin dosveces de la forma siguiente:
void dosveces (int *a)

//suma 10 a i

i cambiar a 15, ya que r_i es simplemente otro nombre para i.

Utilizando tipos referencia, se puede reescribir la funcin dosveces


para multiplicar un entero por 2 de un modo ms simple:
void dosveces(int
{
a *= 2;
}
int x = 5;

& a)

// llamada pasada por referencia


{
*a *= 2;
}

dosveces (x);
cout << x= << x << endl;

aok.qxd

26/11/99 13:51

Pgina 551

C FRENTE A C++

El siguiente programa contiene un procedimiento trivial denominado


max () , que toma parmetros referencia y devuelve una referencia a uno de

551

La funcin tpica intercambio empleada en ordenacin de datos


diseada en C es:

ellos.
// estilo C
#include <iostream.h>
int& max(int &a, int &b)
{
if (a>b)
return a; return b;
}
void main
{
int x = 20, y = 30;
max(x,y)--;
cout << x << y << endl;
}

void intercambio(int
{
int aux;

*a, int *b)

aux = *a;
*a = *b;
*b = aux;
}
...
//llamada a la funcin intercambio
intercambio(&i1, &i2);

La salida de este programa es:


Una versin C++ de intercambio ser:
20

29
// estilo C++

El mismo efecto se hubiera podido realizar tambin con punteros, pero


no haba sido tan legible.
int i;
incremento (i);
...
void incremento (int & variable_referencia)
{
variable_referencia++;
}

void intercambio(int &a, int &b)


{
int aux = a;
a = b;
b = aux;
}
...
//llamada a la funcin intercambio
intercambio (i1,i2);

Una referencia ordinaria se debe inicializar con alguna variable del tipo
apropiado. Por ejemplo, una referencia a un tipo double se debe inicializar
con una variable double:
double di;
double &rd1 = di;

//conforme, rd1 es un alias de di

Un programa completo que hace uso de los parmetros referencias a


travs de la funcin es:
//Programa C++ que utiliza una funcin intercambio
//para intercambiar dos valores int

no con una (const double):

#include <iostream.h>

const double d2 = 3.0;


double &rd2 = d2;
//error

int main()
{
void intercambio(int &xptr, int &yptr);
int s = 10, t = 20;

ni con una constante double.


double &rd3 = 4.0;

// error

cout << Antes de intercambio, s=

<< s << t=, t= << t << endl;

aok.qxd

26/11/99 13:51

552

Pgina 552

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

intercambio(s,t);
cout << Despues de intercambio, s= << s << , t= << t << endl
;
return 0;
}
void intercambio(int &x, int &y)
{
int aux;
aux = x;
x = y;
y = aux;
}

C++ pasa automticamente la informacin de la direccin de il e i2


como argumentos a la funcin intercambio.
La diferencia entre un puntero a algo y una referencia a algo es que el
puntero necesita ser desreferenciado y la referencia no.
Cuando se usan como parmetros funcin, las referencias C++ son
similares a parmetros var en Pascal y Modula-2. Las referencias son
particularmente tiles cuando se pasan estructuras y objetos grandes a una
funcin. Utilizando una referencia para un parmetro slo se pasa la direccin, no la estructura completa o el objeto. Esta accin no slo ahorra espacio de pila y tiempo, sino que facilita el uso de los parmetros estructura/
objeto dentro de la propia funcin.
Los parmetros referencia son eficientes y se deben por eficiencia utilizar siempre que estructuras grandes se pasen a funciones. A veces se desea
pasar algo por referencia, incluso aunque no se desee modificar el valor.
Esto se puede hacer con el calificador const:

El siguiente programa pasa un tipo de dato estructura por referencia:


//programa demo referencia: visualiza una estructura
//utilizando referencias para pasar la estructura
//programa C++ que visualiza informacin de empleado
#include <stdio.h>
struct empleado
{
long numero;
//identificacin de empleado
char *nombre, *telefono;
//nombre y telfono
int edad;
//edad del empleado
};
int main()
{
void ver_emp(const empleado &emp);
empleado emp;
emp.numero = 1001;
//llenar informacin
emp.edad = 46;
emp.nombre = Mark Mackoy;
emp.telefono = 91-4374220;
ver_emp(emp);
//escribir empleado
return 0;
}
void ver_emp (const empleado &e) //referencia a empleado
{
cout << Empleado: << e.numero << endl;
cout << Nombre: << e.nombre endl;
cout Edad: e.edad << endl;
cout << Telefono: << e.telefon << endl;
}

void ref(const int &datosuno);

A.17.

SOBRECARGA

La funcin ref aceptar un valor entero (datosuno) pasado por referencia, pero, dado que tiene definido const, significar que no se puede
cambiar. El calificador const permite utilizar referencias eficientes sin
sacrificar integridad de los datos.
Como ya se ha comentado, aunque las referencias son muy similares a
los punteros, no son punteros. No se pueden utilizar para asignar memoria
dinmica, ni se pueden manipular matemticamente. El propsito final de
las referencias es permitir que las funciones cambien sus argumentos y que
acepten estructuras y objetos como parmetros de un modo ms claro.

C++ aade dos propiedades muy importantes a la capacidad de una funcin.


Se pueden tener mltiples funciones con igual nombre mediante un procedimiento denominado sobrecarga. Adems, C++ permite definir sus propias
funciones para operadores simblicos tales como +, , o bien *.
La sobrecarga es un concepto con doble sentido. Su tarea ms evidente
es permitir que el mismo nombre de una funcin sea utilizado por diferentes implementaciones de la funcin. Menos evidente, pero no por ello
menos importantes es la caracterstica de sobrecargar operadores creando
funciones que se invocan cuando se utiliza un operador simblico. Ambas

aok.qxd

26/11/99 13:51

Pgina 553

C FRENTE A C++

caractersticas son muy potentes y exigen un conocimiento juicioso y prudente por parte del programador.

A.17.1.

Sobrecarga de funciones

En C, como en la mayora de los lenguajes de computadoras, cada funcin


debe tener un nico nombre. A veces esto puede ser enojoso. Por ejemplo,
en C existen diferentes funciones que devuelven el valor absoluto de un
argumento numrico. Dado que dichas funciones realizan tareas similares
pero trabajan con diferentes tipos de datos, se requieren, pues, tres funciones diferentes con nombres distintos:
int abs(int i);
long labs(long l);
double fabs(double d);

C ++ resuelve esta paradoja, permitiendo crear tres funciones diferentes


con el mismo nombre. Esta es la propiedad denominada sobrecarga. Por
ejemplo, en C++ se pueden definir estas tres funciones para declarar la funcin abs:

El compilador C++ selecciona la funcin correcta comparando los tipos


de argumentos en la llamada con los que se especifican en la declaracin de
funcin. As pues, se pueden utilizar las funciones anteriores como sigue:

//se llama a abs(int)


//se llama a abs(long)
//se llama a abs(double)

Otro ejemplo de funcin sobrecargada es sort, que ordena arrays o listas de diferentes tipos:
void
void
void
void

sort(int a[], int n);


sort(float a[], int n);
sort(char *a[], int n);
sort (int a[]);

double calcular(int)

float calcular(int)

ya que su lista de argumentos es idntica.


Las funciones sobrecargadas deben diferir al menos en el tipo o nmero de parmetros que aceptan.

El siguiente programa implementa cuatro funciones suma, cada una de


ellas sobrecargada para realizar operaciones de suma de enteros, reales,
cadenas (concatenacin) y suma de un entero y una constante (42), todas
ellas con dos argumentos, excepto la ltima, que slo tiene un argumento:
#include<string.h>

double suma(double a, double b)


{
return a+b;
}
char *suma(char *a, char *b)
{
strcat(a,b);
return a;
}

int i, difer = -5;


long desplazar;
double x;
i = abs(difer);
desplazar = abs (-21956L);
x = abs (-455);

Cuando se sobrecargan funciones en C++ se tiene que asegurar que el


nmero y tipo de argumentos de todas las funciones sobrecargadas son diferentes. C++ no permite sobrecarga de funciones que difieran slo en el tipo
de valor devuelto. Por consiguiente, no puede sobrecargar funciones tales
como

int suma(int a, int b)


{
return a+b;
}

int abs(int x);


long abs(long 1);
double abs(double d);

553

int suma(int i)
{
return i + 42;
}
main()
{
int i = suma (42, 17);
double d = suma(42.0, 17.0);
char s1 [] = abc;
char s2 [] = xyz;
suma (s1, s2);
}

aok.qxd

26/11/99 13:51

554

Pgina 554

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

Asegrese que los tipos diferentes de los parmetros de las funciones


sobrecargadas son realmente tipos diferentes. Un tipo typedef es simplemente un alias de un tipo existente y no constituye un tipo original de su
propiedad. As, el siguiente segmento de cdigo no es correcto:
typedef INT int;
// ambos prototipos son idnticos
void deferror(int x);
void deferror(INT x);

El ejemplo anterior no se compilar correctamente, debido a que el


compilador no tiene medio de diferenciar entre las dos versiones de deferror. Un INT es slo otro nombre para un int. const y punteros referencia en una funcin pueden diferir en el uso del calificador const, como
sucede en este fragmento de cdigo:
void func(char *ch);
void func(const char * ch);
int main()
{
const char c1 = a;
char c2 = b;
func(&c1);
func(&c2);

//llamada a void func(const char *ch);


//llamada a void func(char *ch);

Es muy mala prctica de programacin tener funciones sobrecargadas


que realizan acciones diferentes. Las funciones con igual nombre deben
tener el mismo propsito general. Crear una implementacin de la funcin
abs que devuelva la raz cuadrada de un nmero le producir con seguridad
confusin y muchos quebraderos de cabeza.
Le sugiero que utilice las funciones sobrecargadas con moderacin. Su
propsito final es proporcionar un nombre nemotcnico para funciones
similares pero con estructuras ligeramente diferentes. El uso abusivo de
funciones sobrecargadas puede hacer un programa ilegible.

A.17.2.

Aplicacin de sobrecarga de funciones

La funcin visualizar escribe cualquier tipo de objeto en la salida estndar: una versin visualiza un tipo empleado, otra versin una cadena, otra
un tipo int, etc. Para conseguir esta caracterstica se sobrecarga la citada
funcin.

//Programa C++ que visualiza diferentes objetos con


//sobrecarga de funciones: archivo ver.cpp
#include <stdio.h>
struct empleado
{
long numero;
char *nombre, *telefono;
int edad;
};
void
void
void
void

//nmero de empleado
//nombre y nmero de telfono
//edad de empleado

visualizar(const empleado &e); //visualizar prototipos


visualizar(char *s);
visualizar(int i);
visualizar(long 1);

int main()
{
empleado emp;
emp.numero = 1001;
emp.edad = 46;
//rellenar info de empleado
emp.nombre = Mark Mackoy;
emp.telefono = 99-4374220;
visualizar(emp);
//escribir un empleado
return 0;
}
void visualizar(const empleado &e)
{
visualizar(Empleado: ); visualizar(e.numero);
visualizar(\n);
visualizar(Nombre:
); visualizar(e.nombre);
visualizar(\n
);
visualizar(Edad:
); visualizar(e.edad);
visualizar(\n);
visualizar(Telefono: ); visualizar(e.telefono)
visualizar(\n);
}
void visualizar(char *s)
{
cout *s;
}
void visualizar(int i)
{
cout << i;
}
void visualizar(long 1)
{
cout << 1;
}

aok.qxd

26/11/99 13:51

Pgina 555

C FRENTE A C++

Cuando se llama a visualizar, el compilador decide a qu versin


llamar examinando los tipos de los parmetros que se pasan. Con visualizar(emp), por ejemplo, se pasa un tipo empleado, de modo que se ejecuta la versin visualizar que espera un empleado. Sin embargo, con
visualizar (e.edad) se pasa un int, as que se ejecuta la versin de
visualizar que espera un tipo int.
La aplicacin anterior se puede mostrar con ms claridad recurriendo a
implementar el archivo de especificacin empleado.h, el archivo de
implementacin empleado.cpp y una funcin principal que hace uso de
dichos archivos.

555

}
void visualizar(const char * s) {
cout << s;
}
void visualizar(const int i){
cout << i;
}
void visualizar (const long 1) {
cout << 1;
}

//FICHERO: empleado.h
//FICHERO (ARCHIVO): principa.cpp
#ifndef EMPLEADO
#define EMPLEADO

#include empleado.h
int main() {
empleado emp;

struct empleado {
long numero;
char * nombre;
char * telefono;
int edad;
};
void
void
void
void

visualizar(const
visualizar(const
visualizar(const
visualizar(const

emp.numero = 1001;
emp.edad = 46;
emp.nombre = Mark Mackoy;
emp.telefono = 91-437422011;
empleado & e);
char * s);
int i);
long l);

visualizar(emp);
return 0;
}

#endif
//FICHERO(ARCHIVO): empleado.cpp
#include empleado.h
#include <stdio.h>
void visualizar(const empleado & e){
visualizar(Nmero:);
visualizar(e.numero);
visualizar(\n);
visualizar(Nombre:);
visualizar(e.nombre);
visualizar(\n);
visualizar(Telfono:);
visualizar(e.telefono);
visualizar(\n);
visualizar(Edad:);
visualizar(e.edad);
visualizar(\n);

A.17.3.

Sobrecarga de operadores

Al igual que C++ permite definir diferentes funciones con el mismo nombre
pero con variacin en sus argumentos, tambin permite redefinir el significado de operaciones tales como +, , *, %, + =, =, ..., para cualquier clase.
En otras palabras, se puede sobrecargar el significado de los operadores. La
sobrecarga de operadores es un concepto interesante que en la mayora de
los lenguajes existe, aunque adquiere su mxima potencia en C + +
As por ejemplo, se pueden sumar dos enteros utilizando el operador +:
a = 5 + 2;

y tambin se pueden sumar dos nmeros reales (float) utilizando el


mismo operador:
a = 5.5 + 2.8;

aok.qxd

26/11/99 13:51

556

Pgina 556

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

Se utiliza el mismo operador para realizar la misma funcin sobre dos


tipos de datos diferentes. El operador + est sobrecargado para realizar la
suma de dos tipos enteros en el primer caso y la suma de dos tipos reales en
el segundo.
Veamos otro ejemplo. El operador * se utiliza para multiplicar dos tipos
de datos:
a = a * b;

Sin embargo, el operador * se puede tambin utilizar para especificar un


tipo puntero cuando se declara:

El operador new puede ser sobrecargado y utilizarse de dos formas diferentes:


new tipo
new tipo[nmero de elementos]

asigna un nico item o elemento


asigna un array

char *car1, *car[40];


// Asignacin de un carcter
car1 = (char*) malloc(1);
car1 = new char;

//Estilo C ANSI
//Estilo C++

// Asignacin de una cadena de 40 caracteres


car40 = (char*) malloc(40);
//Estilo C ANSI
car40 = new char[40];
//Estilo C++

int *ptr;

La sentencia anterior declara ptr como un puntero a un tipo entero. El


operador * se puede utilizar tambin para desreferenciar una variable puntero a fin de manipular el contenido de lo que se almacena en la posicin en
memoria que apunta ptr:

double *doble1, *doble50;


// Asignacin de un tipo doble
doble1 = (double*) malloc(sizeof(double));//Estilo C ANSI
doble1 = new double;
//Estilo C++

*ptr = 5;

La sentencia anterior establece el contenido de la posicin en memoria


almacenada en ptr a 5. Este es otro caso de sobrecarga de operadores.

A.18.

ASIGNACIN DINMICA DE MEMORIA

La asignacin dinmica de memoria permite que un programa en ejecucin


pueda hacer uso del almacenamiento denominado montculo (heap). La
asignacin dinmica de memoria proporciona a un programa gran flexibilidad, ya que el programa puede decidir durante la ejecucin cunta memoria
se utiliza y para qu propsito. En C, la memoria se asigna mediante las funciones de biblioteca malloc y free. C++ define un nuevo mtodo de hacer
asignacin dinrnica mediante los operadores new y delete. Los operadores new y delete permiten a los programadores controlar asignacion y
liberacin del almacenamiento tipo montculo.

A.18.1.

El operador new

El operador new es ms sencillo de utilizar que la funcin malloc() cuando los tipos de las variables a asignar dinmicamente se vuelven complejas.
Compare en el ejemplo siguiente la sintaxis de las asignaciones de memoria que utilizan malloc() y la sintaxis de las que utilizan new.

// Asignacin de un array de 50 elementos tipo double


doble50 = (double*) malloc(50 *sizeof(double));
//Estilo C ANSI
doble50 = new double[50];
//Estilo C++
struct nudo {
int valor;
nudo *izquierda;
nudo *derecha;
};
nudo *nudo],

*nudoN;

//Asignacin de un nudo
nudo1 = (nudo*) malloc (sizeof(nudo)); //Estilo C ANSI
nudo1 = new nudo;
//Estilo C++
// Asignacin de N nudos
int N;
cout << cuantos nudos:?;
cin >> N;
nudoN = (nudo*) malloc(N*sizeof(nudo)); //Estilo C ANSI
nudoN = new nudo[N]
//Estilo C++

Declara una matriz de 20 enteros con malloc:


{
int *p;

aok.qxd

26/11/99 13:51

Pgina 557

C FRENTE A C++

...
p = (int *) malloc (20 * sizeof(int));
...
free(p);

557

Mtodo C
int *P=(int*) malloc (sizeof (int));

Mtodo C++

A diferencia de malloc(), que es una funcin, new es un operador que se


aplica a un tipo de datos T. El operador new le reenva un puntero sobre un bloque de memoria capaz de contener el nmero de objetos de tipo T requerido; la
utilizacin del operador sizeof () con new es intil, pues new conoce
automticamente el nmero de bytes necesarios para cada objeto de tipo T. De
igual forma, el puntero devuelto por new se asigna directamente a un puntero
de tipo T*, sin que sea necesaria una conversin explcita. Al contrario que
malloc(), el operador new efecta una verificacin de tipos:
nudo1 = new doble;// ERROR: conversin p(double*)->(nudo*)

Una funcin tradicional clsica que utiliza memoria dinmica es:


void func(void)
{
int *i;
i = (int*)malloc(sizeof(int));
*i = 10;
printf(%d,*i);
free(i);

int *P = new int;

Utiliza new y delete en lugar de malloc() y free() siempre que sea


posible. Los operadores new y delete utilizarn verificacin de tipos y
trabajan en unin con constructores y destructores.

A.18.2.

El puntero nulo/cero

Si new no puede asignar la cantidad solicitada de memoria, porque por


ejemplo no queda bastante memoria disponible, qu sucede? En este caso,
la funcin malloc() devuelve un puntero NULL (constante definida en la
biblioteca estndar de ANSI C que manipulan punteros: <stdef.h>,
<stdlib.h>, <stdio.h>, etc.).
El operador new reenva el valor 0 (cero). En efecto, la constante 0
(cero) es un valor legal para un puntero C + +; adems, la constante 0 es
compatible con todos los tipos de punteros; el puntero 0 juega el mismo
papel en C++ que la constante NULL en ANSI C. El sistema para comprobar
si la memoria solicitada ha sido asignada realmente es:

En C++, la funcin anterior se puede rescribir as:


void func()
{
int *i = new int;
*i = 10;
cout << * i;
delete i;
}

La sintaxis C++ es ms clara y ms fcil de utilizar. Para asignar un


array de 10 enteros, utilice la sentencia siguiente:
int *i = new int[10];

Otra expresin de inicializacin es

int *tab_10_ent = new int[10];


if(tab_10_ent == 0)
{
// ... falta memoria
}

A.18.3.

El operador delete

El operador delete libera la memoria asignada con new. Este operador funciona de modo similar a la funcin free() para la memoria asignada con
malloc(). No se puede utilizar free()sobre un puntero inicializado con
new, ni delete sobre un puntero inicializado con malloc(). Los formatos
de delete son:
delete direccion

int *ptri = new int[0];

que asigna almacenamiento para un tipo entero (int), inicializa el almacenamiento a 0 y a continuacin guarda un puntero al almacenamiento en la
variable ptri.

delete []direccion

Libera un espacio previamente asignado por new


a la direccin indicada.
Libera espacio asignado si es un array; versiones
antiguas de C++ exigan n (nmero de elementos a destruir).

aok.qxd

26/11/99 13:51

558

Pgina 558

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

// archivo deletenew.cpp
void main()
{
double *d;
d = new double;
//Asignacin de un solo objeto
*d = 12.34;
delete d;
//Liberacin de un solo objeto
d = new double[10];
//Asigna un array de objetos
for(int i=0; i>10; i++)
d[i] = double(i) / 7.0;
delete[]d;
//Liberacin de un array de objetos
//Estilo C
struct Paciente
char nombre [20]
char sexo;
unsigned id;
};
struct Paciente *p;
p = (struct Paciente));
malloc (size(Paciente));
/* ... */
free (p);

//Estilo C++
struc Paciente {
char nombre [20];
char sexo;
unsigned id;
};
struct Paciente *p;
p = new Paciente;
//...
delete p;

El operador delete simple se utiliza para liberar la memoria asignada a un nico objeto, y el operador delete [] cuando se asigna un array o
tabla de objetos. En este ltimo caso no es necesario precisar el nmero de
objetos inicialmente asignados.
Los operadores new y delete sustituyen ventajosamente a las funciones
malloc() y free() para todos los problemas de asignacin dinmica de
memoria. Sin embargo, estos operadores alcanzan su mayor rendimiento en la
gestin correcta de clases en C++, autorizando la inicializacin de un objeto
que pertenece a una clase despus de la asignacin dinmica de ese objeto.

A.18.4.

Ventajas de new y delete

new es superior a malloc por varias razones:

1. new conoce cunta memoria se asigna a cada tipo de variable.


2. malloc debe indicar cunta memoria asignar.
3. new provoca que un constructor se llame para el objeto asignado;
malloc no puede.
new es mucho ms limpia que malloc. Con malloc se tiene que declarar
explcitamente cunta memoria asignar y se debe utilizar conversin forzosa de
tipos (cast). Con malloc es fcil producir errores, pero con new simplemente
basta especificar el tipo de objeto que est creando y new realiza el resto.

int *p = new(int);
int *p = new int[10];

//llamada como una funcin


//declara un array de 10 enteros

Aunque new es til para asignar memoria a variables de tipos incorporados, la potencia real reside en asignar objetos dinmicos que tienen constructores. Cuando new se utiliza para tales objetos, entonces se llama
automticamente uno de los constructores.
reloj *r = new reloj(12,30,45); // asigna e inicializa
delete libera memoria dinmica asignada por new:
int *p = new int;
delete p;
reloj *r = new reloj(4,15,55); //asigna reloj
delete reloj;
//libera reloj
delete produce una llamada al destructor en este orden:

1. El destructor se llama.
2. La memoria se libera.
delete es ms segura que free(), ya que protege al intentar liberar
memoria apuntada por un puntero nulo.

A.19.

ORGANIZACIN DE UN PROGRAMA C++

Un programa C++ se construye sobre la base de archivos .cpp y .h, estructurados sobre la base de un archivo principal de la funcin main, con extensin .cpp.
Archivo principal: nomina.cpp
#include empleado.h
...
main ()
{
...
}

Cabecera clase: empleado.h


class empleado{
...
};

Implementacin de la clase: empleado. cpp


#include empleado.h
...
empleado :: empleado (int 1, char *n, float s)
{
...
}
void empleado :: ver_salario (float horas)
{
...
}

aok.qxd

26/11/99 13:51

Pgina 559

C FRENTE A C++

Archivo de cabecera de la clase


//empleado.h
#ifndef H_EMPLEADO
#define H_EMPLEADO
class empleado {
...
};
#endif

Archivo fuente de la clase


//empleado.cpp
#include <stdio.h>
#include <string.h>
#include empleado.h

//nomina.cpp
#include empleado.h
...
main()
{
...
}

A.19.1.

Evitar definiciones mltiples

En cada archivo de cabecera que tiene una clase se debe verificar, en primer
lugar, que el archivo no ha sido ya incluido en este archivo. Esto se realiza
mediante un indicador (macro) del preprocesador. Si el indicador no est activado, el archivo no se incluye; se debe activar el indicador y declarar la clase.
Si el indicador est activado, la clase ha sido ya declarada, de modo que se
ignora el cdigo que declara la clase. El archivo de cabecera ser similar a ste:
#ifndef INDICADOR_CLASE
#define INDICADOR_CLASE
//Declaracin de la clase
#endif INDICADOR_CLASE

Como se puede ver, la primera vez que el archivo de cabecera se incluye la declaracin de la clase se incluir por el procesador, pero se ignorar
la definicin de la clase en todas las siguientes ocasiones.
El nombre de la macro o indicador puede ser cualquier nombre nico,
pero un mtodo fiable a seguir es tomar el nombre del archivo de cabecera
de sustituir el punto de la extensin por un subrayado y aadir delante o despus del indicador o macro una H (de header) y un subrayado, o cualquier
otra palabra similar que recuerde el nombre del archivo de cabecera.
//archivo de cabecera: PRUEBA.H
#ifndef PRUEBA_H_
#define PRUEBA_H_

class uno {
int i, j, k;
public :
llamar() {i = j = k = 0;}
};
#endif //PRUEBA_H_

En resumen, un archivo de cabecera en C++ se construye normalmente

empleado: :empleado (int i, ...)

Archivo principal

559

as:
#ifndef NOMBRE_CLASE
#define NOMBRE_CLASE
//especificacin de la clase
//que slo incluir el archivo fuente una vez
#endif

Esto permite que un archivo de cabecera se pueda incluir muchas veces


en un programa, pero slo se incluye el contenido del archivo una vez. Esto
puede ocurrir, por ejemplo, en la siguiente situacin, donde un programa utiliza las especificaciones siguientes de las clases para un Coche y una Persona, que contienen ambos la inclusin de una especificacin de una clase
para contener un nombre.
Especificacin de la clase Persona

Especificacin de la clase Coche

#include nombre.h
//utiliza la clase Nombre
class Persona {
//especificacin de la clase
};

#include nombre.h
//utiliza la clase Nombre
class Coche {
//especificacin de la clase
};

A.19.2.

Evitar incluir archivos de cabecera


ms de una vez

Se deben utilizar en los archivos de cabecera lneas de directivas condicionales:


#ifndef _DEMO_H
#define _DEMO_H
//Declaraciones que se
incluyen una vez
...
#endif

//empleado.h
#ifndef H_EMPLEADO
#define H_EMPLEADO
class empleado{
private:
int id;

aok.qxd

26/11/99 13:51

560

Pgina 560

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

...
public:
empleado(int i, char *n, float w);
...
};

Existe el problema de tener el mismo archivo de cabecera incluido ms


de una vez en una compilacin de archivos fuente. El problema con la inclusin de un archivo de cabecera ms de una vez es que las definiciones que
contiene se multiplicarn y en muchos casos esta circunstancia producir
errores de compilacin.
Se puede evitar el problema de tener mltiples definiciones fcilmente.
Para ello se puede utilizar en cada archivo de cabecera las directivas del
compilador #ifndef , #define y #endif para colocar una proteccin a
sus definiciones. El mtodo es el indicado anteriormente para definir la
clase empleado.
La idea bsica consiste en definir constantes macros para cada archivo de cabecera. Estas constantes se denominarn guardianes de macros y
se utilizarn para guardar contra compilaciones mltiples de archivos de
cabecera.
La primera vez que se compila el archivo de cabecera empleado.h, el
valor de la guardia de la macro H_EMPLEADO est indefinido. Por consiguiente, el archivo de cabecera completo se compilar incluyendo la sentencia que define un valor para H_EMPLEADO.
Si el archivo de cabecera se incluyera ms de una vez en el mismo
archivo fuente, o bien directa o indirectamente, el compilador ver que
H_EMPLEADO est definido y saltar sobre el contenido del archivo de cabecera despus de la primera inclusin.
#include <stdio.h>
#include <string.h>
#empleado.h Declaracin clase
#ifndef H_EMPLEADO
#define H_EMPLEADO
class empleado{
private:
int id;
char nombre[40];
float tasa;

public:
empleado(int i, char *n, float s);
void ver_salario(float horas);
};
#endif
//empleado.cpp, implementaciones
#include <stdio.h>
#include <string.h>
#include empleado.h
empleado :: empleado(int i, char *n, float s);
{
id = i;
strcpy(nombre,h);
tasa = s;
}
void empleado :: ver_salario(float horas)
{
cout<< Empleado: << id << : << nombre << endl;
cout << Horas trabajadas: << horas << endl;
cout << Cantidad pagada: << horas*tasa << endl;
}
#include empleado.h
int main ()
{
empleado mortimer(1, juan mortimer,1500);
empleado mackoy(2, pepe mackoy,2200);
mortimer.ver_salario(400);
mackoy.ver_salario(5200);
return 0;
}

Una ejecucin del programa anterior dara una salida similar a la


siguiente:
Empleado:1:juan mortimer
Horas trabajadas: 400.000
Cantidad pagada: 600000.000
Empleado:2:pepe mackoy
Horas trabajadas: 5200.000
Cantidad pagada: 11440000.000

aok.qxd

26/11/99 13:51

Pgina 561

C FRENTE A C++

561

RESUMEN
C++ es una extensin del lenguaje C, que se conoci en sus orgenes con el nombre
de C++ con clases. El inventor de C++, Bjarne Stroustrup, denomin a C++ a
better C (un C mejor).
La mayor atribucin al mundo de la programacin de C++ ha sido la clase.
Adems, C++ ha aadido a ANSI C nuevas palabras reservadas y operadores, funciones en lnea y sobrecargadas, operadores sobrecargados, nuevas tcnicas de gestin de memoria y otras caractersticas complementarias.
En la actualidad, la versin que ha sido estandarizada por el comit ANSI es la

nmero 3, que soporta esencialmente las caractersticas de genericidad y manejo de


excepciones.
ANSI C y C++ utilizan una sintaxis casi idntica, as como los mismos tipos de
bucles, tipos de datos, punteros y otros elementos.
Los compiladores ms usuales son AT&T versin 3.0, Borland C++ 4.5 y 5
Turbo C++ 4.5 y Visual C++ 5.0/6.0, todos ellos siguen prcticamente la norma
AT&T C ++ 3.0.

EJERCICIOS

A.1. Explicar cul es la razn por la que el siguiente programa se detiene con un
mensaje Divide error:
//errordiv.cpp
#include <stdio.h>
int valor;
main ()
{
int n = 100/valor;
printf ("n = % da n",k);
return 0;

A.2. Escribir un programa que solicite un nombre, a continuacin, visualice el mensaje Hola seor/seora x, donde x es reemplazada por el texto introducido.
A.3. Escribir un programa que solicite un nmero entero con signo, a continuacin
visualice el nmero equivalente sin signo en cdigo decimal y hexadecimal.
A.4. Escribir un programa que determine si un nmero entero es par o impar.
A.5. Escribir un programa que solicite un nmero entre 1 y 100. Si se introduce un
nmero de valor fuera de rango, el programa debe visualizar un mensaje de
error y volver a solicitar la introduccin de un nmero.
A.6. En matemticas, el factorial de n (Nmero entero no negativo) se define
mediante la ecuacin:
n! = 1 * 2 * 3 * ... * n;

Nota: El factorial de 0 es 1 (!0 = 1)


El factorial de 1 es 1 (!1 = 1)
El factorial de 2 es 2 (! 2 = 2 * 1 = 2)
A.7. Escribir funciones que calculen el volumen (V) y la superficie (S) de una esfera, utilizando las frmulas:
V = 4/3 3

S = 4 r 2

A.8. Una serie armnica se define mediante la serie:


1 + ... + 1/n
1+1/2 +
3
Escribir una funcin que devuelve el nmero de trminos requeridos para
cumplir la expresin [series armnicas >lmite].
A.9.

Escribir un programa que solicite repetidamente introducir parejas de nmeros, hasta que al menos un nmero de la pareja sea cero. Por cada pareja, el
programa debe utilizar una funcin para calcular la media armnica de los
nmeros.
Media armnica = 2.0 * x * y /(x + y)

A.10.Escribir una funcin que calcule la longitud de una cadena que es un argumento.
A.11. Disear y escribir una funcin que haga notar una serie de valores de una lista
una posicin a la derecha. Es decir, dados los valores 10, 11, 12, 13, 14, la llamada a la funcin cambia la lista a 14, 10, 11, 12, 13, una nueva llamada cambia a 13, 14, 10, 11, 12, etc.

aok.qxd

26/11/99 13:51

562

Pgina 562

PROGRAMACIN EN C++. ALGORITMOS, ESTRUCTURAS Y OBJETOS

A.12. Escribir una funcin que devuelva la moda de una serie de valores reales
(double) almacenados en un array.
A.13. Declarar una estructura que represente un nmero de telfono (cdigo del
pas, cdigo del rea prefijo provincial y nmero). Declarar asimismo
una estructura anidada con dos nmeros de telfono: una para comunicacin
por voz y el otro para fax.
Definir un array que contenga 50 estructuras del tipo nmero de telfono.

A.14. Escribir una funcin que tome un argumento, la direccin de una cadena e
imprima la cadena una vez. Si se proporciona un segundo argumento int y
no es cero, la funcin imprime la cadena un nmero de veces igual al nmero de veces que la funcin ha sido llamada en ese punto.

También podría gustarte