[C con Clase] Nueva duda con listas abiertas

Steven Richard Davidson stevenrichard.davidson en gmail.com
Mie Oct 24 04:48:58 CEST 2007


Hola Roland,

On 10/23/07, Roland <raedura en yahoo.es> wrote:
> De nuevo saludos a todos.
>
> Ahora me ocurre lo siguiente:
>
> Dispongo de una lista abierta (llamada listaClase), y una clase (denominada ClaseA), que contiene un método (llamado DevolverDat) que pretende obtener datos de la lista abierta sin tener que solicitarlo a través del "Main".
>
> Cuando ejecuto este programa, compuesto por tres ficheros, me da el valor del miembro de la lista abierta la primera vez que llamo al método "Operar.DevolverDat (Operar2)", pero a partir de ahí, todas las peticiones posteriores me dan datos erróneos, como si se hubiese activado el destructor de la lista abierta. Si eso es así, ¿existe alguna forma de evitarlo?.
>

Tienes varios errores en tu código. Veamos los códigos fuentes.

> // **Programa principal**
>
> #include <cstdlib>
> #include <iostream>
> #include "Claselista.h"
> #include "Clasita.h"
>
> using namespace std;
>
> ClaseA Operar;
> listaClase Operar2;
>

No es necesario ni recomendable declarar variables globales. Si has
hecho esto con motivo de comprobar tu código, entonces bien.

> int main(int argc, char *argv[])
> {
>     Operar2.Insertar (12);
>     Operar2.Insertar (14);
>     cout << "z1 = " << Operar.DevolverDat (Operar2) << endl;

Aquí empiezas a tener problemas porque el destructor de 'ClaseA' ha
sido invocado. Hablo de esto en la definición de 'DevolverDat()' más
abajo.

>     // A partir de aquí todos los datos son erróneos.
>     cout << "z2 = " << Operar2.DevolverDato () << endl;
>     cout << "z3 = " << Operar.DevolverDat (Operar2) << endl;
>     cout << "z4 = " << Operar2.DevolverDato () << endl;
>     Operar2.Borrar ();
>     system("PAUSE");
>     return EXIT_SUCCESS;
> }
>
> // -------------------------------------
> // **ClaseA**
>
> #include <cstdlib>
> #include <iostream>
>

Aquí tienes un problema. Más abajo, usas la clase 'listaClase' y
además invocas una función miembros suya, pero ésta no es definida.
Deberías incluir el fichero de cabecera "Claselista.h".

Sin embargo, esto causará un error con el resto de tu programa, porque
estarías incluyendo "Claselista.h" dos veces: una vez aquí, en
"Clasita.h" y otra vez en "main.cpp". Para asegurar una sola
inclusión, usamos directivas del precompilador. Escribe lo siguiente:

#indef _CLASE_A_
#define_CLASE_A_

// Escribe aquí todo el contenido de "Clasita.h"

#endif

> using namespace std;
>
> class ClaseA {
>    public:
>       int DevolverDat (listaClase Operarbis);
>
>       friend class listaClase;

Esto no es necesario, porque la clase 'listaClase' no accede
directamente a ningún elemento de 'ClaseA'.

>       };
>
>
> int ClaseA::DevolverDat (listaClase Operarbis)
> {
>      return Operarbis.DevolverDato();
> }
>

Aquí tendrás problemas. Al pasar el parámetro original por copia, el
objeto 'Operarbis' es instanciado a través de su constructor copia.
Como no has definido un constructor copia, se usará el de defecto, que
simplemente copia su contenido tal cual. En este caso, se copian los
punteros 'actual' y 'primero'. En general, esto es _muy_ grave, ya que
los punteros son direcciones de memoria y no la información
directamente. Esto es lo que se llama una copia de baja profundidad.
Lo que te interesa hacer es copia la información. Para esto, tenemos
que seguir los punteros hasta llegar a los datos. Esto se llama una
copia profunda.

Por esto mismo, se nos permite definir nuestras propias versiones para
los constructores, constructores copia, y destructores.


Ahora bien, como no estás haciendo otra cosa que invocar una función
miembro de la clase 'listaClase', pasa este parámetro por referencia.
Esto sería,

class ClaseA
{
   public:
      int DevolverDat( listaClase &Operarbis );
};


int ClaseA::DevolverDat( listaClase &Operarbis )
{
     return Operarbis.DevolverDato();
}


Desde el punto de vista del diseño, deberías aceptar una referencia a
un objeto constante, ya que no tienes intención de modificar el
contenido del objeto referido. Esto es,

class ClaseA
{
   public:
      int DevolverDat( const listaClase &Operarbis ) const;
};


int ClaseA::DevolverDat( const listaClase &Operarbis ) const
{
     return Operarbis.DevolverDato();
}

Esto significa que 'listaClase::DevolverDato()' también deberá ser una
función constante.


Espero que todo esto te ayude.

Steven




Más información sobre la lista de distribución Cconclase