Professional Documents
Culture Documents
de la laguna
Programación Orientada a Objetos en C++
Hagamos una revisión de lo aprendido acerca de los beneficios que trae consigo
el uso de asignación dinámica de memoria.
1.- Los objetos pueden ser creados de manera dinámica, cuando no se sabe
cuantos objetos se iran a necesitar hasta el momento en que esta corriendo el
programa.
2.- Los objetos pueden ser creados de manera dinámica cuando no se conoce el
tiempo de vida de un objeto.
Un Arredin nos dá algunas ventajas sobre las listas enlazadas, uno puede
moverse a la parte superior del Arredin y buscar un elemento mediante una función,
llamada por ejemplo sig(), como se haría en una lista enlazada, en este caso también
podemos seleccionar objetos directamente, usando el operador de corchetes y un
índice. La función suma() nos regresa el índice del elemento que fué agregado. Es
Jove - 261 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
posible también encontrar un índice llamando a la función indice(), la cual nos regresa
el valor del indice del elemento actual.
Sintaxis de new
Donde:
Sintaxis de delete.
delete []puntero
Note que para asegurar la operación adecuada del operador delete, se omite el
número de elementos a eliminar. Delete automaticamente elimina todo el espacio
reservado al arreglo y también, en el caso de tipos definidos por el usuario, llama al
destructor para cada elemento del arreglo.
Jove - 262 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
Arredin
enum {fuera = 10};
+arreglo : void
tam : int
cursor : int
error()()
Arredin()()
~Arredin()
suma()()
remueve(int)()
remueve(void *)()
reinicia()()
sig()()
previo()()
indice()()
actual()()
tope()()
operator[]()()
cuenta()()
class Arredin {
enum { fuera = 10 }; // Cuanto incrementar el arreglo cuando
void **arreglo; // corre fuera del espacio asignado.
int tam;
int cursor;
void error(char *msg = "");
public:
Arredin();
~Arredin();
Jove - 263 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
#endif // DINARRE_H_
memset
V. regresado Un puntero a s.
Jove - 264 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
Jove - 265 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
Arredin::Arredin()
{
tam = fuera;
cursor = 0;
arreglo = new void *[tam];
memset(arreglo, 0, sizeof(void *)*tam);
}
Arredin::~Arredin()
{
delete []arreglo;
}
Jove - 266 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
void Arredin::reinicia()
{
cursor = 0;
while( (arreglo[cursor] == 0) && (cursor < tam) )
cursor++; // Encuentra el primer elemento NO CERO
}
void *Arredin::sig()
{
if(cursor == tam - 1) // Ultimo elemento.
return 0;
// No es el último elemento, incrementa hasta que encuentra
// una localidad no vacia, o el final.
while(arreglo[++cursor] == 0)
if( cursor == tam - 1) // No más elementos en la lista
return 0;
return arreglo[cursor];
}
void *Arredin::previo()
{
if(cursor == 0)
return actual();
while(arreglo[--cursor] == 0)
if(cursor == 0) // Tope de la lista
return 0;
return arreglo[cursor];
}
void *Arredin::operator[](int x)
{
if(x < 0 || x >= tam)
error("operator[] - Indice fuera de Rango");
return arreglo[x]; // Incluso si esta vacio.
}
Jove - 267 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
int Arredin::cuenta()
{
int cnt = 0;
for(int x = 0; x < tam; x++)
if(arreglo[x])
cnt++;
return cnt;
}
class cadena {
char *cad;
public:
cadena(char *msg = "") { cad = msg; }
char *cp() { return cad; }
friend ostream& operator<<(ostream& s, cadena *sp);
};
void main()
{
Arredin da;
Jove - 268 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
OBSERVACIONES.
Jove - 269 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
Este programa crea un arreglo de cadenas, procuramos que sean más cadenas
que el valor de fuera, de tal forma de poder probar la parte dinámica del Arredin, para
hacer ésto declaramos un objeto del tipo Arredin llamado da.
Para imprimir la lista tal y cual fué almacenada en la clase Arredin, primero
ponemos el puntero a arreglo en su inicio, y luego llamamos a la función actual(), la
cual nos regresa el puntero a donde apunta indice. Al hacer el cast a cadena se llama a
la función operattor<<() la cual nos imprime la cadena correspondiente de acuerdo a la
dirección almacenada en arreglo. Mediante el do-while, imprimimos todas las cadenas,
tal y como fueron almacenadas.
A continuación, vamos a buscar la subcadena "00PS", en todas las cadenas
cuyas direcciones son almacenadas en arreglo. Para ello utilizamos la función strstr().
La función strstr() es una función de la librería del paquete, la cual definimos a
continuación:
strstr
Jove - 270 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
Este operador, primero verifica que rm tenga un valor válido, si no lo tiene llama
a la función error(), para indicar que ha ocurrido un error, si rm esta dentro del rango,
regresa un puntero al elemento cuyo índice fué dado como argumento (rm).
En seguida se presenta una copia de la función, para mayor facilidad de su
análisis.
void *Arredin::operator[](int x)
{
if(x < 0 || x >= tam)
error("operator[] - Indice fuera de Rango");
return arreglo[x]; // Incluso si esta vacio.
}
-----------------------------------------
NOTE que mientras se hace referencia a un puntero desde el objeto da, se debe
hacer siempre un cast a un puntero a cadena (cadena *), antes de que pueda ser
utilizado, ésto es necesario ya que si no se utiliza este artificio, el compilador va a
producir un mensaje de error, por intentar una dereferencia a un puntero del tipo void.
-----------------------------------------
Cuando salimos del ámbito del objeto da, se llama a su destructor. El cual nos
elimina del heap, todo el arreglo.
Jove - 271 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
// Programa PLCP66.CPP
// Una clase cadena, la cual maneja cualquier tipo
// de apuntador a caracter (dato static o automático)
#include <iostream.h>
#include <string.h>
class cadena {
char *cad;
public:
cadena(char *msg = "") // Duplica el mensaje como un
{ // dato privado.
cad = new char[strlen(msg) + 1];
strcpy(cad, msg);
}
char *cp() { return cad; }
Jove - 272 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
void main()
{
char *cads = "Este es un mensaje clave";
cadena S(cads);
OBSERVACIONES.
La sentencia:
Jove - 273 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
La librería de ANSI C, nos brinda una función llamada strdup(), la cual asigna
almacenamiento para una cadena, además nos copia la cadena en ese espacio, y nos
regresa la dirección de inicio del espacio asignado, sin embargo strdup() usa la función
malloc() y no el operador new, así que se deberá recordar al liberar la memoria usar
free() y no delete.
En este ejemplo se crea una clase, en donde mediante una función miembro
almacenamos una cadena secreta codificada, usando una llave (dada como cadena)
para su codificación.
Posteriormente dando la llave, podemos reconstruir la cadena.
Veamos un ejemplo:
// PROGRAMA PLCP67.H
// Interface, clase que guarda un cadena de prueba.
// codificado y decodificado
#ifndef ENCODE_H_
#define ENCODE_H_
class code {
char *code_cad;
unsigned char make_key(char *);
public:
code(char *msg, char *key); // Instala un mensaje
char *decode(char *key); // Decodifica y lee
};
#endif // ENCODE_H_
El dato privado, puntero a char code_cad, almacena la dirección del heap, donde
es almacenada la cadena codificada.
Veamos su implementación.
Jove - 274 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
// Programa PLCP67.CPP
// Uso de asignación dinámica a cadenas
#include <iostream.h>
#include <string.h>
#include "plcp67.h"
Jove - 275 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
// Programa PLCP67A.CPP
// Aplicación de la clase "code"
#include <iostream.h>
#include "plcp67.h"
void main()
{
code mensa_oc("Esta es la prueba de cadena", "abre");
cout << mensa_oc.decode("abre") << endl;
}
OBSERVACIONES.
Cuando se usa new para crear un objeto, se asigna la memoria suficiente para
almacenar los elementos de datos del objeto. (estos elementos normalmente se
encuentran en la pila y en el área de almacenamiento de memoria static) y a
continuación se llama al constructor del objeto. En el caso de que el objeto sea un
conjunto de otros objetos (ya sea a través de una herencia de clases o porque el objeto
contenga objetos miembro), los constructores son llamados siguiendo un orden; En
primer lugar se llamará al constructor de la clase base, luego el/los constructor(es) para
los objeto miembro, y por último el constructor de la clase derivada.
Jove - 276 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
Cuando se usa delete, para destruir un objeto, él cual fué previamente creado y
almacenado en el heap, la computadora, realiza primero un limpiado del objeto
mediante la llamada a su destructor. Si el objeto es un conglomerado de otros objetos el
destructor es llamado en un determinado orden, siendo el orden inverso del orden en el
cual se llamaron los constructores; primero se llama al destructor de la clase derivada,
luego a los destructores de los objetos miembro, y finalmente al destructor de la clase
base.
// Programa PLCP68.CPP
// Análisis del orden de llamadas
// a constructores y destructores.
// Usando herencia y objetos miembro.
#include <iostream.h>
class miembro {
int x;
public:
miembro(int i) {
cout << "Constructor de miembro : " << i << endl;
x = i;
}
~miembro() {
cout << "Destructor de miembro : " << x << endl;
}
};
class base {
int xx;
miembro M;
public:
// Veamos como se inicializa un objeto miembro.
base(int a, int b) : M(b) {
cout << "Constructor de base : " << a << ", "
<< b << endl;
xx = a;
}
~base () {
cout << "Destructor de base : " << xx << endl;
}
};
Jove - 277 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
void main()
{
{
cout << "Creando objeto de derivada D(1,2,3)" << endl;
derivada D(1,2,3);
cout << "Derivada sale de ámbito" << endl;
} // Aquí se llama el destructor
cout << "Creando un objeto de derivada en el heap Dp(4,5,6)"
<< endl;
derivada *Dp = new derivada(4,5,6);
cout << "Destruyendo el objeto en el heap" << endl;
delete Dp;
}
OBSERVACIONES.
En el caso de usar un objeto de una clase, como dato miembro de otra clase, el
objeto deberá ser inicializado de una manera especial. Refiriendonos al constructor de
la clase donde fué definido un objeto, como dato miembro. El objeto miembro es
Jove - 278 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
llamado después de la lista de argumentos, pero antes del cuerpo del constructor. A
esta parte del constructor se le conoce como lista de inicialización del constructor.
Cuando una clase hereda de otra clase, la clase base deberá ser inicializada
antes del cuerpo del constructor de la clase derivada.
Jove - 279 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
Si notamos el orden fué el inverso, con que fueron llamados los constructores.
delete []op;
También es posible usar esta notación para arreglos de tipos predefinidos, pero
este tipo de datos no tienen destructores, en un objeto sin destructor, los argumentos
son ignorados. Sin embargo es siempre una buena idea emplear esta notación cuando
se destruyen arreglos.
// Programa PLCP69.CPP
Jove - 280 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
class linda {
static int i;
public:
linda() {
cout << "Llamada a constructor " << ++i << endl;
}
~linda() {
cout << "Llamada a destructor " << i-- << endl;
}
};
void objeto_auto()
{
linda A[5];
}
void objeto_dina()
{
linda *B = new linda[4];
delete []B;
}
int linda::i = 0;
void main()
{
cout << "Llamada objeto_auto........" << endl;
objeto_auto();
cout << "Llamada a objeto_dina......" << endl;
objeto_dina();
}
OBSERVACIONES.
Llamada objeto_auto.......
Llamada a constructor 1
Llamada a constructor 2
Llamada a constructor 3
Llamada a constructor 4
Jove - 281 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
Llamada a constructor 5
Llamada a destructor 5
Llamada a destructor 4
Llamada a destructor 3
Llamada a destructor 2
Llamada a destructor 1
Llamada a objeto_dina......
Llamada a constructor 1
Llamada a constructor 2
Llamada a constructor 3
Llamada a constructor 4
Llamada a destructor 4
Llamada a destructor 3
Llamada a destructor 2
Llamada a destructor 1
Podemos observar que tanto para el caso de objetos creados en la pila, como
para objetos creados en el heap, usando new y delete, la llamada al constructor y la
llamada al destructor se realiza para cada elemento del arreglo.
Jove - 282 -
INSTITUTO TECNOLOGICO
de la laguna
Programación Orientada a Objetos en C++
En C++ es bastante común utilizar el valor 0, para indicar que un puntero esta
vacio. Esto es perfectamente soportado por delete, se puede llamar a delete con un
puntero a 0, lo cual no tiene ningún efecto, por lo que al liberar memoria usando delete,
no es necesario verificar si el puntero es 0 o no lo es.
La memoria asignada de manera dinámica solamente debrá ser liberada una vez,
si se libera más de una vez, puede ser desastroso.
Jove - 283 -