Está en la página 1de 28

Programacin Orientada a Objetos

3 Clases manejo de memoria dinmica en C++ - 1 -



Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

Clases y manejo de memoria dinmica en C++

Repaso a las funciones de manejo de memoria dinmica en C............................................................................1
Funcin calloc()...................................................................................................................................................1
Funcin malloc() .................................................................................................................................................2
Funcin realloc() .................................................................................................................................................2
Funcin free() ......................................................................................................................................................3
El operador new frente a malloc ............................................................................................................................3
El operador delete frente a free..............................................................................................................................8
Sobrecarga de new y de delete................................................................................................................................9
Sobrecarga de new y delete respecto a una clase especfica.............................................................................11
Clases con punteros miembros .............................................................................................................................14
El Puntero this ......................................................................................................................................................22
Funciones estticas y el puntero this.................................................................................................................24
Paso y retorno de objetos......................................................................................................................................24
Paso y retorno de referencias a objetos................................................................................................................26
Ejercicios propuestos ............................................................................................................................................27



Repaso a las funciones de manejo de memoria dinmica en C

Funcin calloc()
Prototipo: void *calloc(int num, int tam);
Archivo cabecera: stdlib.h
Valor devuelto: Devuelve un puntero al primer byte del bloque de memoria reservada, o un
puntero
NULL en el caso de no haberse podido reservar el bloque de memoria solicitado
Finalidad: Reserva un bloque de memoria para almacenar num elementos de tam bytes cada
uno de ellos. Todo el bloque de memoria queda iniciado a 0.

num: indica el nmero de elementos con la misma estructura que ocuparn el bloque de memoria reservado.
tam: indica el tamao en bytes de cada uno de los elementos que van a ocupar el bloque de memoria
reservada.

La cantidad de memoria reservada viene determinada por el resultado que se obtiene al multiplicar el nmero de
elementos a almacenar en el bloque de memoria por el tamao en bytes de cada uno de esos elementos, es decir,
num * tam.

El uso de esta funcin se puede ilustrar con el siguiente ejemplo:

int n=100, *pt;
...
pt = ( int * ) calloc (n, sizeof(int));

En este ejemplo la funcin calloc reserva un bloque de memoria de n enteros, y retorna un puntero void a dicho
bloque, o NULL si n fuera 0 o se produjera un error al no poder reservar suficiente espacio para reservar la

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 2 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

memoria solicitada. Sobre el puntero que se retorna se debe hacer una operacin de cast apropiada, para
asignarlo al puntero del tipo que se est tratando.

Funcin malloc()
Prototipo: void *malloc(int tam);
Archivo cabecera: stdlib.h
Valor devuelto: Devuelve un puntero al primer byte del bloque de memoria reservada, o un
puntero
NULL en el caso de no haberse podido reservar el bloque de memoria solicitado
Finalidad: Reserva un bloque de memoria de tam bytes.

tam: indica el tamao en bytes del bloque de memoria que se desea reservar.

La cantidad de memoria reservada ser de tam bytes.

El uso de esta funcin se puede ilustrar con el siguiente ejemplo:

struct Registro *ptr_reg;
ptr_reg = ( struct Registro * ) malloc (sizeof (struct Registro));

La funcin malloc reserva un bloque de memoria lo suficientemente grande como para acoger por completo al
tipo de dato, y retorna un puntero void a dicho bloque, o NULL si el tamao del argumento es 0 o se ha
producido un error al no poder reservar suficiente espacio para alojar al tipo de dato. Sobre el puntero que se
retorna se debe hacer una operacin de cast apropiada, para asignarlo al puntero del tipo que se est tratando.

Funcin realloc()
Prototipo: void *realloc(void *ptr, int nuevo_tamao);
Archivo cabecera: stdlib.h
Valor devuelto: Devuelve un puntero al primer byte del bloque de memoria reservada, o un
puntero
NULL en el caso de no haberse podido reservar el bloque de memoria solicitado
Finalidad: Cambia el tamao del bloque de memoria apuntada por ptr al nuevo tamao
indicado por nuevo_tamao

ptr: puntero que apunta al bloque de memoria reservado.
nuevo_tamao: valor en bytes que indica el nuevo tamao del bloque de memoria apuntado por ptr y que
puede ser mayor o menor que el original.

En estas tres funciones es importante comprobar que el puntero devuelto por ellas no es un puntero nulo
(NULL) antes de hacer uso del bloque de memoria reservado.


Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 3 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

Funcin free()
Prototipo: void free(void *ptr);
Archivo cabecera: stdlib.h
Valor devuelto: Ninguno
Finalidad: Libera el bloque de memoria apuntada por ptr y que previamente ha sido asignado
mediante malloc() o calloc().

ptr: variable puntero que debe contener la direccin de memoria del primer byte del bloque de memoria que
deseamos liberar. En caso de que no sea un puntero previamente reservado por malloc() o calloc(), la
llamada a la funcin free() puede ocasionar una parada o interrupcin del sistema.



El operador new frente a malloc

En el lenguaje C, la regin de memoria que est disponible a la hora de la ejecucin recibe el nombre de heap.
En C++ el espacio de memoria disponible se conoce como almacenamiento libre
1
. La diferencia entre los dos se
encuentra en las funciones que se utilicen para el acceder a esta memoria.

El mtodo para solicitar memoria del heap en C se basa en el uso de la funcin malloc y sus derivadas (calloc,
realloc, ...). En C++ no es correcto utilizar malloc para alojar de forma dinmica una nueva instancia de una
clase. La razn es que si se usa malloc, se pierden las ventajas que nos ofrecen los constructores, ya que se llama
al constructor de la clase cada vez que se crea un objeto. Si se usa malloc para crear un objeto, se tiene un
puntero a un bloque de memoria sin iniciar. Entonces se pueden hacer llamadas a mtodos con objetos que no
estn bien construidos, y que por lo tanto van a dar resultados errneos.

La tcnica ms adecuada es utilizar la alternativa que ofrece C++ mediante el operador new.

El operador new conoce la clase del objeto, o el tipo de la variable, que se quiere alojar en el almacenamiento
libre. De esta forma este operador llama automticamente al constructor que corresponda, dependiendo de los
argumentos que se especifiquen, para iniciar la memoria que ha reservado.

La forma de utilizar este operador es la siguiente:
<nombre_puntero> = new <nombre> [<argumentos>];
De la sintaxis de new se puede deducir que no es una funcin, y que por lo tanto no tiene una lista de
argumentos entre parntesis. Es un operador que se aplica al nombre del tipo, pero no se tiene que realizar un
cast
2
ni utilizar el operador sizeof para determinar su tamao, porque new conoce el tipo de dato y su tamao.

Si new no encuentra espacio para alojar lo que se le pide, devuelve 0
3
.

El operador new reemplaza a las funciones malloc y calloc de la biblioteca estndar de C, pero no sustituye a
realloc. La funcin realloc puede ser simulada, pero la aproximacin que se haga supondr siempre un aumento

1
Free store.
2
El compilador comprueba que el tipo del puntero que devuelve new y el tipo del puntero al que se asigna son
del mismo tipo. En caso contrario genera un error.
3
En C++ un puntero nulo vale 0 en lugar de NULL.

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 4 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

de las lneas del cdigo fuente, as como conocer el tamao original del espacio reservado mediante el puntero
que se va cambiar. Pero afortunadamente se puede utilizar generalmente realloc para cambiar el tamao del
espacio reservado con new.

Como se ha dicho, con new se puede reservar espacio para cualquier tipo de dato, siendo muy utilizado para
reservar espacio para matrices
4
. Un ejemplo:
float *centros;
centros = new float[numero];

Para ilustrar todo lo visto hasta el momento del operador new se ha realizado este sencillo programa de ejemplo:

// Programa: malloc versus new
// Fichero: MALVNEW.CPP

#include <iostream.h>
#include <string.h>
#include <stdlib.h>

class Prueba {
int i, j;
char *s;
public:
Prueba() { // Constructor por defecto
i=j=5;
s=new char[5];
strncpy(s, "Hola", 5);
}

Prueba(char *cad, int a, int b) { // Constructor con parmetros
i=a; j=b;
s=new char[strlen(cad)+1];
strcpy(s, cad);
}

~Prueba () {delete [] s;} // Destructor

int miembro(void) { // Funcin para mostrar los datos de la clase
cout << "\n" << s << "\n";
return i+j;
}

void cambia(void) { // Funcin para ilustrar el uso de realloc
int i=strlen(s);
s=(char *)realloc(s, strlen(s)+2);
s[i++]='+';
s[i]='\0';
}

}; // Fin de la definicin de la clase


4
Las matrices que se reservan de forma dinmica no pueden recibir valores iniciales. Cuando se trate de una
matriz de objetos se debe realizar un constructor por defecto, en caso contrario el compilador generar un error.

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 5 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

void main (void)
{
// Creamos un objeto dinmico con malloc
Prueba *P1;
P1=(Prueba *) malloc (sizeof (Prueba));

// Y nos vamos a estrellar: Salen caracteres raros por pantalla e
// incluso se puede colgar el programa
cout << "\n" << P1->miembro() << "\n";


// Creamos un par de objetos dinmicos con new
Prueba *P2, *P3;

P2=new Prueba; // Usa el constructor por defecto
P3=new Prueba("Hola Caracola",4,3); // Usa el constructor con parmetros

// Todo es correcto
cout << "\n" << P2->miembro() << "\n";
cout << "\n" << P3->miembro() << "\n";

// Usamos realloc
P2->cambia();
P3->cambia();

// Y todo sigue OK
cout << "\n" << P2->miembro() << "\n";
cout << "\n" << P3->miembro() << "\n";


// Se libera la memoria que hemos reservado
// Es buena tcnica de programacin liberar el espacio reservado
// con malloc mediante la funcin free, y el espacio reservado con
// new con el operador delete.
free(P1);
delete P2;
delete P3;
}

El operador new tiene otra ventaja sobre malloc que todava no se ha tratado.

Es una buena tcnica de programacin controlar los posibles errores derivados de la falta de espacio a la hora de
reservarlo en el manejo dinmico de la memoria.

Cuando se programa en ANSI C, el programador tiene que construirse sus propios mecanismos para detectar
que se ha producido un error cuando se ha llamado a malloc
5
.

Sin embargo en C++, se puede seguir utilizando estas mismas tcnicas de programacin cuando se utiliza el
operador new
6
, o por el contrario se puede elegir una alternativa ms conveniente que nos ofrece este lenguaje.


5
Se recuerda que cuando esto ocurre malloc devuelve NULL.
6
Ya que new devuelve 0 si no hay espacio.

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 6 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

C++ define un puntero a funcin, de forma que cuando ocurre un error, la funcin a la que apunta el puntero es
llamada. La definicin de dicho puntero es:
void (* _new_handler)();

El uso de este puntero tiene el inconveniente de no ser estndar. Por ello se recomienda el uso de una funcin de
biblioteca definida en new.h, y que se llama set_new_handler, que toma como argumento un puntero a funcin,
y asigna la funcin al puntero _new_handler. Aunque este segundo mtodo es ms comn, y por lo tanto ms
conveniente, tampoco es estndar
7
.

// Programa: Manejo de errores en la reserva de espacio con new
// Versin Borland C++
// Fichero: NEW_ERR.CPP

#include <iostream.h>
#include <new.h>
#include <stdlib.h>

#define PASO 20000

void MemoriaInsuficiente(void)
{
cerr << "\n\aEl espacio en el Almacenamiento Libre agot.\n";
exit(1);
}

void main (void)
{
long total=0;
set_new_handler ( MemoriaInsuficiente );

// Otra manera de hacerlo con Borland C++
//_new_handler = MemoriaInsuficiente;

for(;;) {
char *espacio = new char[PASO];
total+=PASO;
cout << "Llevamos reservados " << total << " bytes \n";
}
}



7
Se hicieron pruebas con los compiladores Borland C++ 3.1, Visual C++ 1.0, y DJGPP 2.6.0. Slo el
compilador de Borland acept la definicin directa _new_handler = funcion;
Cuando se utiliz la funcin set_new_handler(funcion); el compilador de Borland y el DJGPP, funcionaron
sin problemas, pero para realizar esta operacin con Visual C++ hubo que utilizar la funcin _set_new_handler
y redefinir el prototipo de la funcin que manejaba el error.


Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 7 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

// Programa: Manejo de errores en la reserva de espacio con new
// Versin Microsoft C++
// Fichero: NEW_ERR.CPP

#include <iostream.h>
#include <new.h>
#include <stdlib.h>
int MemoriaInsuficiente(size_t size)
{
cerr << "\n\aEl espacio en el Almacenamiento Libre se agot.\n";
exit(1);
return 0;
}

void main (void)
{
long total=0;
_set_new_handler ( MemoriaInsuficiente );

for(;;) {
char *espacio = new char[20000];
total+=20000;
cout << "Llevamos reservados " << total << " bytes \n";
}
}


En resumen:

Ventajas de new frente a malloc.
Calcula de forma automtica el tamao del tipo para el que se est reservando memoria
Proporciona el tipo correcto del puntero
Es posible dar valores iniciales al objeto que se crea mediante el operador new
La notacin es mucha ms clara
Se puede definir una funcin que se encargue del manejo de los errores por falta de espacio en la zona de
almacenamiento libre

Cuando usar uno u otro.
Tratar de usar ambos sistemas de manejo de memoria dinmica a la vez puede acarrear posibles problemas
de inconsistencias
Se recomienda el uso en C++ del operador new siempre que sea posible
8
, desechando para casos muy
concretos el uso de las funciones derivadas de malloc
En caso de seguir empleando las funciones derivadas de malloc, recordar que cuando se vaya a reservar
espacio para una clase, se debe utilizar el operador new, o crear unos mtodos que permitan iniciar las
variables privadas, y llamarlos nada ms reservar el espacio con malloc




8
Las ventajas que se obtienen son obvias.

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 8 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

El operador delete frente a free

El operador delete se puede decir que es para new, lo que free para malloc. Esto es, libera los bloques de
memoria, dejndolos listos para futuras reservas.

La sintaxis de delete es muy sencilla:
delete <nombre_puntero>;

Cuando se trata de liberar el espacio asociado un puntero a un objeto, delete de forma automtica llama al
destructor.

El operador delete se debe utilizar slo con punteros que retorne new. Mientras que la funcin free se debe usar
con punteros que apunten a zonas de memoria reservadas mediante funciones derivadas de malloc. De no
hacerse as, y dependiendo de los compiladores, puede causar graves problemas
9
. Si se intenta liberar dos veces
un mismo puntero, los resultados pueden ser catastrficos. Estas dos circunstancias deben ser controladas por el
programador, ya que el compilador no las detecta.

Se puede liberar un puntero nulo sin consecuencias adversas.

El uso de delete con los tipos preestablecidos no tiene misterios, salvo en el caso de las matrices, que se debe
usar la siguiente sintaxis:
delete [tamao] <nombre_puntero>;

En la mayora de los compiladores basta con poner los corchetes vacos, ya que ignoran el nmero que se ponga
entre ellos.
Un sencillo ejemplo del uso del operador unario delete puede ser el siguiente:

// Programa: Uso de delete
// Fichero: DELETE1.CPP

#include <iostream.h>
#include <new.h>

void main (void)
{
int *i, *vi;

i=new int;
*i=6;

vi= new int[2];

vi[0]=0; vi[1]=1;

cout << *i << " " << vi[0] << " " << vi[1] << "\n";

delete i; // Elimina el objeto
delete [] vi; // Libera una array de objetos
}


9
Si se intenta liberar la memoria que se ha reservado mediante new para una instancia de una clase mediante
free, se est perdiendo la llamada al destructor como consecuencia inmediata.

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 9 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

Sobrecarga de new y de delete

En C++ es posible redefinir los operadores new y delete sobrecargndolos, si se quiere construir un
procedimiento de manejo de memoria personalizado.
Los esqueletos de las funciones que sobrecargan estos operadores son:

void *operator new (size_t tamao)
{
// Reserva dinmica
return puntero_void;
}

void operator delete (void puntero)
{
// Liberar memoria a la que apunta el puntero
}

El operador new toma como argumento un tipo size_t que es un tipo entero que puede contener el mayor bloque
individual de memoria que se pueda reservar. El nmero de bytes a reservar se indican mediante el parmetro
tamao. Adems cualquier operador new que se cree debe devolver un puntero void.

En cuanto al operador delete toma como argumento un puntero de tipo void, el cual apunta a la zona de
memoria que debe liberar. Adems cualquier operador delete que sea creado por el programador no debe
retornar nada.

Si se redefine el operador new de esta forma se sigue llamando al constructor de la clase cuando se tiene una
instancia dinmica de una clase.

Sin embargo, puede surgir algn tipo de problemas, cuando se sobrecargan estos operadores, con el uso de
realloc debido a que el nuevo sistema de manejo de memoria dinmica utilice las mismas tcnicas de manejo de
memoria que las funciones de biblioteca del C.

Para ilustrar la sobrecarga de los operadores new y delete se va ha realizar un sencillo programa que inicie el
contenido del bloque de memoria que se quiere reservar a 0 antes de utilizarlo
10
.

// Programa: Sobrecarga de los operadores new y delete
// Fichero: N&DOVER1.CPP

#include <iostream.h>
#include <string.h>
#include <stdlib.h>

void *operator new ( size_t s ) {
void *ptr=calloc(1, s);
return ptr;
}

void operator delete ( void * ptr ) {
free ( ptr );
}

10
Se utilizar la funcin calloc porque sta inicia a 0 todo el bloque de memoria que reserva.

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 10 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)



Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 11 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

void main(void) {
float *p=new float[5];
for (register int i=0; i<5; cout << " " << p[i++]);
delete [] p;
}

Tambin se puede redefinir el operador new de forma que tome parmetros adicionales, especificando los
argumentos entre parntesis.
Para ilustrar esta caracterstica se va a modificar el programa anterior, de forma que en lugar de rellenar el
espacio en memoria con ceros, se inicie con un carcter determinado.

// Programa: Sobrecarga de los operadores new y delete
// Fichero: N&DOVER2.CPP

#include <iostream.h>
#include <string.h>
#include <stdlib.h>

void *operator new ( size_t s, int relleno )
{
void *ptr;
if ( (ptr = malloc(s) )!=NULL)
memset(ptr, relleno, s);
else
exit(1);

return ptr;
}

void operator delete ( void * ptr )
{
free ( ptr );
}

void main(void)
{
char *p=new ('/') char[40];
for (register int i=0; i<40; cout << p[i++] << " ");
delete [] p;
}



Sobrecarga de new y delete respecto a una clase especfica
Esta caracterstica va a permitir personalizar el manejo de memoria dinmica para una clase individual.

Cuando se sobrecargan estos operadores con respecto a una clase en concreto, implica que cuando se utilicen
estos operadores con cualquier otro tipo de datos se van a emplear los operadores new y delete originales, o
aquellos que se hayan sobrecargado de forma global.

Para sobrecargar estos operadores para una clase se tienen que declarar dos funciones miembro que tengan por
nombre operator new y operator delete. Estos operadores tienen precedencia sobre los operadores new y
delete globales.

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 12 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

Cuando se va a procesar el operador new para una instancia de una clase, el compilador primero comprueba si
estn definidos para dicha clase, y en caso afirmativo utiliza las versiones especficas de la clase. En caso
contrario, si han sido sobrecargados globalmente, emplea estas nuevas versiones globales, y en ltimo caso
utilizara los operadores estndar new y delete.

Para ilustrar la sobrecarga de estos operadores respecto de una clase, se presenta el siguiente ejemplo:

// Programa: Sobrecarga de los operadores new y delete respecto de una
// clase
// Fichero: N&DOVER3.CPP

#include <iostream.h>
#include <string.h>
#include <stddef.h>

#define NOMBRES 10

class Nombre {
char nombre[25];
public:
Nombre ( const char * );
void Presenta ( void ) const;
void *operator new (size_t s);
void operator delete (void *ptr);
~Nombre() {}; // Destructor que no hace nada
};

// Memoria para manejar un nmero fijo de instancias de la clase Nombre
char memo[NOMBRES] [sizeof (Nombre)];
int en_uso[NOMBRES];

// Funciones miembro de la clase Nombre
Nombre::Nombre ( const char *cad )
{
strncpy (nombre, cad, 25 );
}

void Nombre::Presenta ( void ) const
{
cout << "\n" << nombre << "\n";
}

// Sobrecarga de los operadores new y delete para la clase Nombre
void * Nombre::operator new ( size_t s )
{
for (int p=0; p < NOMBRES; p++) {
if ( !en_uso[p] ) {
en_uso[p] = 1;
return memo + p;
}
}

return 0;
}


Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 13 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

void Nombre::operator delete ( void * ptr )
{
en_uso[ ( (char *)ptr - memo[0] ) / sizeof ( Nombre ) ] = 0;
}

void main ( void )
{
Nombre * directorio [NOMBRES];
char nombre[25];

for (register int i=0; i<NOMBRES; i++) {
cout << "\Introduce el nombre #" << i+1 << ": ";
cin >> nombre;
directorio[i] = new Nombre ( nombre );
}

for (i=0; i<NOMBRES; i++) {
directorio[i] -> Presenta();
delete directorio[i];
}

}

Notas:
Este programa aprovecha la caracterstica de conocer que no habr nunca ms de un nmero pequeo de
instancias de clases al mismo tiempo, pero que se estn alojando y desalojando de forma continua. As se
crean unas versiones especficas de new y delete, que trabajan mucho ms rpido que la versin global.
Se crea una matriz global que pueda contener todas las instancias de la clase (memo), y se hace que los
operadores new y delete manejen dicha matriz.
Se cuenta tambin con un vector de enteros de tantas entradas como filas tiene la matriz de instancias,
llamado en_uso, y que va a servir como banderas, para indicar si la correspondiente entrada en la matriz
memo est en uso o no.
Cuando se ejecuta la sentencia directorio[i]=new Nombre( nombre ), el compilador invoca al operador
new propio de la clase. Este encuentra un entrada libre en la matriz memo, y retorna su direccin. Despus
de esto el compilador llama al constructor de la clase, el cual usa el espacio en la matriz, y lo inicia con una
cadena de caracteres. Finalmente, se asigna a la entrada de la matriz directorio un puntero al objeto recin
creado.
Por su parte, cuando se ejecuta la sentencia delete directorio[i], el compilador llama al destructor, que en
este ejemplo no hace nada. Despus de lo cual se invoca al operador delete propio de la clase. El operador
delete encuentra la situacin del objeto dentro de la matriz memo y lo marca como libre, con lo que el
espacio est de nuevo preparado para alojar otra cadena.
De lo aqu explicado se concluye que el operador new se llama antes que el constructor, y el operador
delete se llama despus del destructor.




Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 14 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

Clases con punteros miembros

Una prctica habitual es utilizar los operadores new y delete en las funciones miembros de una clase, como ya
se ha visto en varios de los ejemplos que hasta ahora se han presentado.

Pero en este apartado se va a estudiar con ms profundidad esta posibilidad, comentando ciertos problemas que
pueden surgir, y la forma de solventarlos.

Para ello se va a crear una clase Cadena para el manejo de cadenas de caracteres, que el lector puede
personalizar y ampliar como ejercicio prctico de programacin.

CADENA.H

#ifndef __CADENA_H__
#define __CADENA_H__

#include <iostream.h>
#include <string.h>

class Cadena {
char *cadena;
unsigned longitud;
public:
Cadena(void);
Cadena(const char *);
Cadena(char, unsigned);
void CambiaCaracter(int, char);
char MuestraCaracter(int) const;
int Longitud(void) const {return longitud;}
void Muestra(void) const {cout << cadena;}
void Agnadir(const char *);
~Cadena();
};

#endif


CADENA.CPP

// Programa: Clases con punteros miembros. Clase Cadena
// Fichero Principal.
// Fichero: CADENA.CPP

#include "cadena.h"

// Constructores

Cadena::Cadena()
{
cadena=0; // Iniciamos puntero a "null" en C++
longitud=0;
}


Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 15 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

Cadena::Cadena(const char *cad)
{
longitud=strlen(cad);
cadena=new char[longitud+1];
strcpy(cadena, cad);
}

Cadena::Cadena(char c, unsigned n)
{
longitud=n;
cadena=new char[n+1];
memset(cadena, c, n);
cadena[n]='\0';
}

// Funciones miembro de la clase Cadena

void Cadena::CambiaCaracter(int indice, char c)
{
if ( (indice >= 0) && (indice<longitud) )
cadena[indice]=c;
}

char Cadena::MuestraCaracter(int indice) const
{
if ( (indice >= 0) && (indice<longitud) )
return cadena[indice];

return 0;
}

void Cadena::Agnadir(const char *cad)
{
char *tmp;

longitud += strlen(cad);
tmp=new char[longitud+1];
strcpy(tmp, cadena);
strcat(tmp, cad);
delete [] cadena;
cadena=tmp;
}


// Destructor
Cadena::~Cadena()
{
delete [] cadena;
}




Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 16 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

CADDEMO1.CPP

// Programa: Clases con punteros miembros. Clase Cadena
// Fichero Principal.
// Fichero: CADDEMO1.CPP

#include "cadena.h"

void main(void)
{
Cadena Micadena ("esta es mi cadena.");

Micadena.Muestra();
cout << "\n";

Micadena.CambiaCaracter(0, 'E');
Micadena.Muestra();
cout << "\n";

Micadena.Agnadir(" OK !!!!!");
Micadena.Muestra();
cout << "\n";
}

Para almacenar las cadenas nunca es lo ms apropiado utilizar matrices, debido a que en principio se desconoce
las longitudes que stas pueden tener. En su lugar, tal y como se ha hecho en el ejemplo, se puede tener un
puntero a carcter como miembro, y de forma dinmica reservar la cantidad exacta de memoria que necesite
cada instancia de la clase.

El constructor que recibe un puntero a carcter utiliza el operador new para reservar la memoria necesaria para
almacenar la cadena. Despus copia el contenido de la cadena en el espacio reservado. Como resultado de todo
esto se tiene que cada objeto Cadena no es un bloque contiguo de memoria, sino que consiste en dos bloques de
memoria: El primero contiene la longitud y un puntero a la cadena, y el otro almacena la cadena de caracteres
en s.
11


La clase Cadena es un tpico ejemplo que necesita un destructor, ya que cuando se destruye un objeto por salir
del alcance en el que definido, se libera el espacio de memoria que ocupa el primer bloque de forma automtica,
pero el espacio que se reserv con new, debe ser liberado de forma explcita. De lo contrario el espacio con las
cadenas de caracteres no sera nunca liberado, y el programa podra quedarse sin memoria en cualquier
momento.

Pero este ejemplo presenta un posible problema. Supongamos que utilizamos la clase Cadena con el siguiente
programa principal:

// Programa: Clases con punteros miembros. Clase Cadena
// Fichero Principal.
// Fichero: CADDEMO2.CPP


11
Si se utilizar sizeof para calcular el tamao de un objeto Cadena, slo se conseguira en tamao del bloque
que contiene el entero y el puntero. Sin embargo, las diferentes instancias de la clase Cadena pueden tener
cadenas de caracteres de diferente tamao.

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 17 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

#include "cadena.h"
#include <conio.h>

void main(void)
{
Cadena c1("Esta es la primera cadena"),
c2("Esta es otra cadena");

clrscr();

cout << "\nLa cadena c1 es: ";
c1.Muestra();
cout << "\nLongitud de c1 es: " << c1.Longitud() << "\n";
cout << "\nLa cadena c2 es: ";
c2.Muestra();
cout << "\nLongitud de c2 es: " << c2.Longitud() << "\n";

// Asignamos la primera cadena a la segunda, y mostramos
// ambas cadenas, y sus longitudes
c2=c1;
cout << "\nLa cadena c1 es: ";
c1.Muestra();
cout << "\nLongitud de c1 es: " << c1.Longitud() << "\n";
cout << "\nLa cadena c2 es: ";
c2.Muestra();
cout << "\nLongitud de c2 es: " << c2.Longitud() << "\n";

// Ambas tienen el mismo contenido y la misma longitud
// como era de esperar

// Ahora cambiamos algo al objeto c1 y repetimos la
// operacin de mostrar ambos objetos
c1.CambiaCaracter(1, 'S');
cout << "\nLa cadena c1 es: ";
c1.Muestra();
cout << "\nLongitud de c1 es: " << c1.Longitud() << "\n";
cout << "\nLa cadena c2 es: ";
c2.Muestra();
cout << "\nLongitud de c2 es: " << c2.Longitud() << "\n";

// Pero que pasa si yo he cambiado slo la cadena del objeto c1,
// y se han modificado los dos objetos ((( Qu pasaaaaa !!!

// Ahora aadimos algo al objeto c1 y repetimos la
// operacin de mostrar ambos objetos
c1.Agnadir(" :-)))");
cout << "\nLa cadena c1 es: ";
c1.Muestra();
cout << "\nLongitud de c1 es: " << c1.Longitud() << "\n";
cout << "\nLa cadena c2 es: ";
c2.Muestra();
cout << "\nLongitud de c2 es: " << c2.Longitud() << "\n";

// (((( Esto es una ruina !!!! La cadena del objeto c1 ha sido
// modificada correctamente, pero la del objeto c2 se ha ido
// a la ...
}

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 18 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)



Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 19 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

En el ejemplo se han creado dos objetos c1 y c2 de la clase Cadena. Para despus hacer una asignacin de c1 en
c2. Cuando se realiza una asignacin de un objeto a otro, el compilador realizara lo siguiente:

c2.longitud = c1.longitud;
c2.cadena = c1.cadena;

En la asignacin del miembro longitud no hay ningn problema. sin embargo, como el miembro cadena es un
puntero, el resultado de la asignacin es que c1.cadena y c2.cadena apuntan a la misma zona de memoria. Es
decir, ambos objetos comparten la cadena de caracteres.

De forma grfica:


Aqu esta la explicacin de los efectos no deseados que encontrbamos en el programa CADDEMO2.CPP.


Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 20 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

Otros problemas ms graves se pueden llegar a dar cuando el objeto sale del alcance donde fue definido. Cuando
el destructor de la clase se llama para el objeto c1, se elimina dicho objeto liberndose tambin la memoria
donde apuntaba el puntero cadena. Cuando el destructor se llama de nuevo para el objeto c2, se eliminar el
puntero miembro cadena. Pero como los dos miembros cadena de ambos objetos tienen el mismo valor,
significa que un puntero ha sido eliminado dos veces, esto puede tener consecuencias imprevistas.

Adems, el contenido original del miembro cadena del objeto c2 se ha perdido, y ese bloque de memoria no ser
liberado.

Este problema ocurre con cualquier clase que contiene punteros miembro y reserva memoria del
almacenamiento libre.

En conclusin el operador de asignacin que nos ofrece por defecto el compilador, no es adecuado para usarlo
entre clases. La solucin ser reemplazar el que se nos ofrece por defecto por uno escrito por nosotros mismos, y
que realmente realice la asignacin de forma adecuada.

Como ya es sabido, una de las caractersticas del C++ es que se permite la sobrecarga de operadores
12
. Lo que se
va a hacer es dotar al operador de asignacin de un significado especial cuando se refiera a la clase Cadena.

Para redefinir el operador de asignacin se debe crear una funcin miembro que se llame operator=. De esta
forma cuando se vaya a realizar una asignacin entre objetos de la clase Cadena, el compilador utilizar el
operador de asignacin escrito para dicha clase.

El nuevo operador de asignacin puede ser algo como:

// Operador de asignacin

void Cadena::operator= (const Cadena &fuente)
{
longitud = fuente.longitud;
delete [ ] cadena;
cadena = new char[longitud + 1];
strcpy ( cadena, fuente.cadena);
}


12
Que se estudiar con detalle ms adelante

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 21 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

El operador recibe como parmetro una referencia como constante
13
a un objeto Cadena. El resultado ahora es
correcto, y se ilustra en la siguiente figura:

Una vez modificado el fichero cabecera, y el fichero cuerpo de la clase, compilar y ejecutar el programa
CADDEMO2.CPP.

Pero que ocurrira si se realiza una auto asignacin c1 = c1; Esto que parece absurdo, y que casi nadie va a
utilizar tiene otras formas ms comunes:

Cadena *Ptr_cad = &c1;
// Ms adelante ...
c1 = *Ptr_cad;

Lo que ocurrir es que en la definicin del nuevo operador de asignacin, primero borra la cadena de caracteres,
y despus reserva un nuevo espacio, donde copia el contenido del espacio recin reservado en l mismo. Esto
tiene como resultado que se introduce basura, y la prdida de la cadena de caracteres del objeto. Para que el
operador trabaje bien en todos los casos, se debe utilizar el puntero this
14
para prever el caso de la auto
asignacin.

Cuando una clase tiene punteros miembro, se debe tener en cuenta a la hora de trabajar con constructores copia.

Como se vio cuando se trat el tema de los constructores copia, estos iniciaban un objeto con los valores de otro
objeto. Aqu se tiene involucrado el uso del operador asignacin. Pero como se ha visto en este mismo apartado,
el operador de asignacin por defecto nos va a dar resultados errneos si la clase tiene punteros miembro. As si
se hiciera lo siguiente:
Cadena c2(c1);

Se estara iniciando el objeto c2 con los valores del objeto c1, pero al utilizar el operador de asignacin por
defecto, lo que se estara haciendo es que tanto c1 como c2 apuntarn a la misma cadena de caracteres.

13
Indicando que dicho operador no puede modificar el objeto que recibe
14
El puntero this se estudia en el siguiente apartado. Por lo que respecta a la correcta manera de crear el
operador de asignacin para la clase Cadena, realizar el ejercicio 3 de este mismo captulo.

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 22 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

La solucin pasa por construir un constructor copia propio. Como ejemplo se va a escribir el constructor copia
para la clase Cadena.

// Constructor Copia
Cadena::Cadena ( const Cadena &fuente)
{
longitud = fuente.longitud;
cadena = new char [longitud +1];
strcpy (cadena, fuente.cadena);
}

La realizacin del constructor copia es muy similar a la realizacin del operador asignacin. Pero hay algunas
diferencias entre ellos:
Un operador de asignacin acta sobre un objeto que existe, mientras que un constructor copia crea uno
nuevo. Como resultado, un operador de asignacin puede tener que borrar la memoria que se reserv
originalmente para el objeto que recibe los datos.
Un operador de asignacin tiene que comprobar las auto asignaciones. El constructor copia no tiene que
hacerlo, porque en su caso no existen auto asignaciones.
Para permitir asignaciones encadenadas, un operador de asignacin debe retornar *this. Por ser un
constructor, el constructor copia no puede devolver valores.




El Puntero this

Cada vez que se invoca a una funcin miembro, se le pasa automticamente un puntero al objeto que la ha
invocado
Se puede acceder a ese puntero utilizando la palabra reservada this
El puntero this es un parmetro implcito a toda funcin miembro
15

Para acceder a un elemento concreto de un objeto cuando se utiliza el objeto en s, se emplea el operador
punto (.)
Para acceder a un elemento concreto de un objeto cuando se utiliza un puntero al objeto, se emplea el
operador flecha (->)

Cuando se llama a una funcin miembro, el compilador asigna la direccin del objeto al puntero this, y despus
se llama a la funcin. Cada vez que una funcin miembro accede a un dato miembro, se est utilizando de forma
implcita el puntero this.

Por ejemplo considrese el siguiente programa en C++:

#include <iostream.h>

class D {
int i,j,k;
public:
D() {i=j=k=0;}


15
Excepto para las funciones miembro static

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 23 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

void Mostrar(void)
{
cout << "\n" << i << " " << j << " " << k;
}
} A;


void main ()
{
A.Mostrar();
}


Sera equivalente a este otro:

#include <iostream.h>

class D {
int i,j,k;
public:
D() {this->i=this->j=this->k=0;}

void Mostrar(void)
{
cout << "\n" << this->i << " " << this->j << " " << this->k;
}
} A;


void main ()
{
A.Mostrar();
}

A la vista del ejemplo se puede deducir que es lcito el uso del puntero this cuando se accede a los datos
miembro, aunque es del todo innecesario. Tambin es correcto utilizar la expresin *this para referirse al objeto
que ha llamado a la funcin miembro.

As las tres sentencias que aparecen en la siguiente funcin son equivalentes:

void Mostrar(void) {
cout << "\n" << i << " " << j << " " << k;
cout << "\n" << this->i << " " << this->j << " " << this->k;
cout << "\n" << (*this).i << " " << (*this).j << " " << (*this).k;
}

Otro de los usos del puntero this es comprobar si el objeto que se pasa como parmetro a una funcin miembro
es el mismo objeto que llam a dicha funcin. Esto es fundamental para las auto asignaciones. Lo que se hace es
comprobar que la direccin del objeto que se pasa como argumento es diferente del valor del puntero this, si
esto es as se puede hacer la asignacin sin problemas. Sino se sale de la funcin sin hacer nada.

Si se utiliza *this como valor de retorno de una funcin, se puede lograr crear operadores que sean asociativos
bien por la derecha, como es el caso de la asignacin, bien por la izquierda, como ocurre en las sentencias cout
de este tipo cout << a << b << c;

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 24 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

El puntero this es un puntero constante, por lo tanto una funcin miembro no puede cambiar el valor del
puntero, y hacer que apunte a otro sitio. Sin embargo, en las primeras versiones de C++, el puntero this no era
constante, y esto permita al programador hacer asignaciones al puntero this para personalizar el manejo de la
memoria dinmica. Esto ya no est permitido en las ltimas versiones de C++.


Funciones estticas y el puntero this
Cuando en el captulo anterior se abord el tema de las funciones miembro static, se definieron como aquellas
que slo podan trabajar con miembros dato estticos. Esto es debido a que este tipo de funciones carecen de
puntero this.

Pero el problema surge si una funcin necesita de forma imperiosa acceder a un miembro dato de una clase. Para
solucionarlo se le ha de pasar de forma explcita un puntero this. Vase el siguiente ejemplo:

// Programa: Funciones miembro estticas y el puntero this
// Fichero: STTHIS.CPP

#include <iostream.h>

class Prueba {
int a, b;
static int decre;
public:
Prueba () {a=b=0;}
Prueba (int a1, int b1=0) {a=a1; b=b1;}
static int Ejemplo(Prueba *E) {return E->a+E->b-decre;}
};

int Prueba::decre=1;

void main (void)
{
Prueba P1(1,2);
cout << Prueba::Ejemplo (&P1) << "\n";
}



Paso y retorno de objetos

Hay otras dos situaciones, a parte de en las definiciones, en las que un constructor copia se llama:
Cuando una funcin recibe un objeto como parmetro.
Cuando una funcin retorna un objeto.

Supongamos un extracto de programa en C++ en el que se muestra una funcin que recibe un objeto Cadena
como argumento.

// Funcin que recibe un objeto Cadena como argumento
void ProcesaCadena ( Cadena cad )
{
// Usa el objeto cad
}

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 25 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)


void main ()
{
Cadena c1("Cadena de ejemplo");
ProcesaCadena ( c1);
}

La funcin ProcesaCadena recibe un objeto que se pasa por valor. Esto significa que la funcin tiene su propia
copia privada del objeto.

El parmetro de la funcin se inicia con el objeto que se pasa como argumento. El compilador de forma implcita
llama al constructor copia para realizar esta iniciacin.

Si no se define un constructor copia para realizar la iniciacin, el compilador realiza su constructor copia por
defecto, y el objeto cad y el objeto c1 tendran la misma cadena de caracteres, y por lo tanto cualquier
modificacin en la cadena de caracteres de cad modificara la cadena de caracteres del objeto c1.

Tambin habra problemas en cuanto que el objeto cad tiene un alcance local, y por lo tanto al salir de la funcin
se llamara al destructor. Esto significa que el objeto c1 tendra un puntero que apuntara a una zona de memoria
que ya ha sido liberada, lo cual iba a ser poco recomendable.

Ahora supongamos un extracto de fuente en C++ donde se incluye una funcin que retorna un objeto Cadena.

// Funcin que retorna un objeto Cadena
Cadena RetCadena ( void )
{
Cadena valor ( "Esto es una prueba.");
return valor;
}

void main ()
{
Cadena c1;
c1 = RetCadena();
}

La funcin RetCadena retorna un objeto Cadena. El compilador llama al constructor copia para iniciar un
objeto temporal y oculto en el alcance de la llamada, usando el objeto que se especifica en la sentencia return.
Este objeto temporal es usado como parte derecha de la asignacin que hay en el programa principal.

De nuevo, se necesita un constructor copia. En otro caso el objeto temporal compartira la misma cadena de
caracteres que el objeto valor, el cual ser eliminado cuando la funcin RetCadena finalice su ejecucin, y en
consecuencia la asignacin que se hace a c1 no est garantizada.

Como regla a seguir, se debe definir siempre un constructor copia y un operador de asignacin cuando se
tenga una clase que contenga punteros miembro y reserve espacio del almacenamiento libre.




Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 26 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

Paso y retorno de referencias a objetos

En el apartado anterior se ha visto como cada vez que se pasaba un objeto a una funcin por valor, se llamaba al
constructor copia.

Una forma de simular el paso por valor de un objeto, pero sin tener que llamar al constructor copia sera utilizar
referencias a objetos constantes.

Estudiemos el mismo ejemplo que se vio en el apartado anterior, pero ahora la funcin recibe una referencia al
objeto constante.

// Funcin que recibe un objeto Cadena como argumento
void ProcesaCadena ( const Cadena &cad )
{
// Usa el objeto cad
}

void main ()
{
Cadena c1("Cadena de ejemplo");
ProcesaCadena ( c1);
}

Ahora el constructor copia no es llamado porque no se ha construido un nuevo objeto. En su lugar se inicia una
referencia con el objeto que se le pasa. Como resultado se usa el mismo objeto que en la llamada a la funcin.

El uso de la palabra reservada const es debido a que se quiere asegurar la integridad del objeto, esto es, que no
se pueda modificar el objeto en la funcin.

Igualmente que una funcin retorne una referencia en lugar de un objeto es mucho ms eficiente. El constructor
copia no se llama cuando se produce el valor de retorno, porque no se crea un objeto temporal, slo se crea una
referencia temporal.

Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 27 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

Ejercicios propuestos
1. Indicar cul de las siguientes frases es incorrecta y explicar los motivos
a) La funcin delete sirve para liberar zonas de memoria que han sido reservadas mediante new.
b) El uso de malloc est prohibido en C++
c) La funcin set_new_handler sirve para que una funcin determinada se encargue del manejo de los
errores por falta de espacio en el manejo de memoria dinmica mediante el operador new.
d) Cuando se crea un objeto con el operador new no se llama al constructor de la clase a menos que se
indique de forma explcita mediante argumentos.
e) Aunque no se debe, si se usa free para liberar un puntero a una instancia devuelto por new, se llama al
destructor si existe.


2. Reescribir la funcin cambia() del programa MALVNEW.CPP, reemplazando la funcin realloc por una
simulacin de sta mediante el operador new.


3. Tenemos la clase Cadena.
class Cadena {
char *cadena;
unsigned longitud;
public:
Cadena(void);
Cadena(const char *);
Cadena(char, unsigned);
void CambiaCaracter(int, char);
char MuestraCaracter(int) const;
int Longitud(void) const {return longitud;}
void Muestra(void) const {cout << cadena;}
void Agnadir(const char *);
~Cadena();
};
Se ha redefinido el operador de asignacin para dicha clase.

// Operador de asignacin
void Cadena::operator= (const Cadena &fuente)
{
longitud = fuente.longitud;
delete [] cadena;
cadena = new char[longitud + 1];
strcpy ( cadena, fuente.cadena);
}

Escribir de nuevo este operador de asignacin de la clase Cadena, de forma que se admita la auto asignacin:

c1 = c1 o Cadena *ptr_cad = &c1;



Programacin Orientada a Objetos
3 Clases manejo de memoria dinmica en C++ - 28 -

Ingeniera Tcnica en Informtica de Sistemas (3er curso)
Departamento de Informtica y Automtica Universidad de Salamanca (versin Febrero 2003)

4. Modificar de nuevo el operador de asignacin para que ahora tambin permita: c1=c2=c3;


5. Un constructor copia tiene como argumento una referencia a un objeto en lugar de un objeto. Por qu?


6. Crear una clase apropiada para representar el tipo de dato nmero complejo. Un nmero complejo se
representar como (a, b), donde a representa la parte real y b la imaginaria.

Construir adems las funciones apropiadas para:
Asignar valor a un nmero complejo
Imprimir un nmero complejo con el formato (a, b)
Sumar dos nmeros complejos
Restar dos nmeros complejos
Multiplicar dos nmeros complejos

Construir, adems, un pequeo programa principal que compruebe el comportamiento de esta clase.


7. Crear una clase apropiada para representar el tipo de dato rectngulo.
Construir adems las funciones apropiadas para:
Calcular el rea de un rectngulo
Calcular el permetro de un rectngulo
Dados dos rectngulos, determinar cual es el mayor, teniendo en cuenta que el mayor es aquel que tiene
mayor rea.
Dados dos rectngulos, determinar si sin idnticos. Ser idnticos implica que tiene el mismo rea y el
mismo permetro.
Intercambiar los valores entre dos rectngulos
Ordenar un vector de rectngulos, de mayor a menor


8. Incluir a la clase Cadena definida en este documento los siguientes mtodos:
Invertir una cadena
Pasar a maysculas
Determinar si es un palndromo

Construir adems una funcin que permita ordenar de mayor a menor un vector de Cadenas.

También podría gustarte