[C con Clase] Error constructor copia

Steven Davidson srd4121 en njit.edu
Mar Mar 31 19:03:31 CEST 2009


Hola Vicente,

vicente lozano wrote:
> Hola,
> 
> He declarado un constructor copia, pero al hacer la asignacion de un
> new me da un error el compilador que no entiendo.
> 

Ten presente que una asignación no implica un constructor copia. Por 
ejemplo,

class Algo
{
public:
   Algo();
   Algo( const Algo &ref );
   ...
};

int main()
{
   Algo obj1, obj2;  // Constructor: Algo()
   Algo obj3 = obj1;  // Constructor copia: Algo(const Algo &)

   obj2 = obj1;  // Asignación
   ...
}

Las asignaciones tienen que ver con el operador de asignación y no con 
el constructor. Si queremos un comportamiento diferente al de defecto 
para la asignación, entonces tenemos que sobrecargar el operador de 
asignación.

> Las clases son:
> 
> class ProbabilityDistribution {
> 
> gsl_rng * _rnd;
> DistType _distType;
> long double _mu;
> long double _sigma;
> ...
> }
> 
> class Error {
> ProbabilityDistribution _components[];

Me temo que esta declaración no es correcta. O bien creaste un array o 
bien un puntero; esto es,

class Error
{
   ProbabilityDistribution _components[1024];
   ...
};

Usando un puntero, entonces sería:

class Error
{
   ProbabilityDistribution *_components;
   ...
};


Si has declarado este miembro como un array, entonces tienes un error y 
posiblemente otro. Escribes:

_components[0] = new ProbabilityDistribution( ... );

Los tipos no concuerdan; estás haciendo esto,

<ProbabilityDistribution> = <ProbabilityDistribution *>

Es decir, intentas asignar un puntero a un objeto. Como no has 
sobrecargado el operador de asignación, el compilador se queja de que no 
existe un candidato para este operador con los tipos de estos operandos.

Ten presente que al usar un array, ya has instanciado todos los objetos 
según la cantidad del array. Siguiendo el ejemplo que he dado, hemos 
instanciado 1024 objetos de la clase 'ProbabilityDistribution' invocando 
el constructor 'ProbabilityDistribution()' - sin parámetros.

Si en su lugar, '_components' es un puntero, entonces, no tendríamos un 
problema, ya que los tipos de los operandos en la asignación concuerdan; 
esto es,

<ProbabilityDistribution *> = <ProbabilityDistribution *>

Sin embargo, apuntaríamos a un solo objeto, sin tener una lista de objetos.

Aconsejo crear un array dinámico de punteros a 
'ProbabilityDistribution'. Esto es,

class Error
{
   ProbabilityDistribution **_components;
   ...
};

Luego, haríamos esto:

// Creamos el array dinámicamente
_components = new ProbabilityDistribution*[1024];

// Instanciamos un objeto para el primer elemento
_components[0] = new ProbabilityDistribution( ... );

Esto implica que tenemos que liberar la memoria, posiblemente para el 
destructor.

La otra posibilidad es declarar un array (estático) de punteros. Esto sería,

class Error
{
   ProbabilityDistribution *_components[1024];
   ...
};

Con esto, creamos un array de punteros y luego instanciaremos cada 
objeto de cada elemento dinámicamente, según nos interese. Esto es,

_components[0] = new ProbabilityDistribution( ... );


En C++, aconsejaría usar una clase-plantilla estándar que realice estas 
operaciones. Por ejemplo, podrías usar un 'vector<>' que viene a 
representar un array cualquiera. Por ejemplo,

#include <vector>

class Error
{
   vector< ProbabilityDistribution > _components;
   ...
};

También podrías crear un 'vector' de punteros. Esto es,

class Error
{
   vector< ProbabilityDistribution * > _components;
   ...
};

Así, puedes instanciar cada objeto dinámicamente.

> int _ncomponents;
> long double _lastError;
> ...
> }
> 
> 
> Se usa la libreria GSL, libreria matematica que me recomendasteis por
> aqui, pero el error creo que no tiene nada que ver, lo digo solo
> para que sepais de donde viene el gsl_rng y tal.
> 

No veo error en la GSL, pero sí veo un problema con 'gsl_rng *' en la 
clase 'ProbabilityDistribution'. Siempre que diseñes una clase que 
contenga miembros que son punteros, deberías definir un constructor 
copia y sobrecargar el operador de asignación. De lo contrario, estarás 
copiando punteros y no la información apuntada por ello. Esto se llama 
una copia de poca o baja profundidad. Lo que interesa es hacer una copia 
profunda, siguiendo los punteros y copiando toda la información.


Espero haber aclarado las dudas.

Steven





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