[C con Clase] vectores y clases

Steven Davidson srd4121 en njit.edu
Jue Abr 30 22:49:24 CEST 2009


Hola Nelfi,

nelfi hernandez wrote:
> Gracias Steven por tus repuestas, pero hubo cierto error al copiar y
> pegar el codigo, la clase se llama habitantes_dn, no se como pude
> hacer borrado lo que le faltaba, pero en mi codigo fuente esta bien,

¡Qué raro! En fin, si lo tienes bien en tu código fuente, entonces bien 
está.

> pido disculpas por mi error, por lo demas he acatado tus sugerencias,
> y he implemetado un constructor por defecto, lo que intento hacer si
> se puede hacer es crear un vector por ejemplo:
> 
>  vector<habitantes_dn> ID_objeto1
> habitantes_dn ID_objeto2
> 
> y ir metiendo datos con ;
> 
> ID_objeto1.push_back(ID_objeto2);
> 
> Lo que no se es como poder implementar esto, sin tener que delarar
> una estructura, dentro de la clase, espero haber sido lo
> suficientemente explicito.
> 

No veo que necesites crear otra estructura ni anidarla. Las sentencias 
que acabas de escribir son correctas. Por ejemplo,

int main()
{
   vector< habitantes_dn > lista;

   lista.push_back( habitantes_dn() );
   lista[0].agregar();

   lista.push_back( habitantes_dn() );
   lista[1].agregar();
   ...
   return 0;
}

Lo que realmente estamos haciendo es instanciar un objeto temporal para 
luego copiarlo al último elemento. Sin embargo, 'vector' funciona en 
base a crear arrays dinámicos de una cantidad internamente calculada. Es 
decir, 'vector' no aumenta su array interno para un solo elemento, sino 
para varios. Como cada elemento es un objeto, esto significa que al 
crear memoria para un objeto puede suponer la instanciación de varios 
más. Por esto recomendé que definieras un constructor.

Dicho esto, también tenemos que tener en cuenta que al agregar un nuevo 
objeto, estamos copiando ese objeto. Esto implica que necesitamos tener 
un constructor copia. En tu caso, no es necesario definir un constructor 
copia, porque el que existe por defecto nos sirve perfectamente.

El problema que veo con tu implementación de la clase 'habitantes_dn' es 
que no tienes funciones miembros para acceder a los datos privados. Es 
decir, deberías tener lo siguiente:

class habitantes_dn
{
private:
   string              nombre;
   string              apellido;
   unsigned long       cedula;
   unsigned short int  ano_nacimiento;
   string                mes_nacimiento;
   unsigned short int  dia_nacimiento;
   unsigned short int  edad;
   string              provincia;
   string              direccion;
   string              telefono;
   float               estatura;
   float               peso_corporal;
   string              color_piel;
   string              estado_civil;
   string              religion;
   char                puede_votar;

public:

   habitantes_dn(); // Constructor de la clase
   //~habitantes_dn(); // Destructor de la clase

// -- Acceso: lectura y escritura -- //

   const string &Nombre() const  { return nombre; }
   const string &Nombre( const string &ref )
   {
     nombre = ref;
     return nombre;
   }

   const string &Apellido() const  { return apellido; }
   const string &Apellido( const string &ref )
   {
     return apellido = ref;
   }

   unsigned long Cedula() const  { return cedula; }
   unsigned long Cedula( unsigned long ced )
   {
     if( verificar(ced) )  cedula = ced;

     return cedula;
   }

   ...


   // Operaciones
   void agregar();
   void actualizar();
   void ver();
};

Dicho esto, tengo que comentar acerca de las dos primeras funciones que 
creaste a modo de operaciones. Al definir las otras funciones de acceso, 
que acabo de mencionar, no necesitas 'agregar()' ni 'actualizar()' como 
funciones miembros. Quizá sea una buena idea tenerlas como funciones 
globales, pero no como miembros. Por ejemplo,

void agregar( habitantes_dn &obj )
{
   system( "clear" );

   cout << "\n\nAgrege los datos del habitante por favor..."
        << endl << endl;

   cout << "Nombre                   : ";
   getline( cin, str );
   obj.nombre( str );

   cout << "\n\nApellido                 : ";
   getline( cin, str );
   obj.apellido( str );
   ...
}

También aconsejo crear un constructor que admita instanciar un objeto 
pasando los valores necesarios para describir un habitante. Por ejemplo,

class habitantes_dn
{
   ...
   habitantes_dn( const string &nom="",
                  const string &ape="",
                  unsigned long ced=0,
                  unsigned short int anno=0,
                  const string &mes="",
                  unsigned short int dia=0,
                  ... );
   ...
};

De esta manera, podemos instanciar un objeto directamente con toda la 
información escrita explícita e implícitamente. Por ejemplo,

int main()
{
   vector< habitantes_dn > lista;

   lista.push_back( habitantes_dn("Nelfi","Hernandez") );
   lista[0].Puede_Votar( 'S' );

   lista.push_back( habitantes_dn("Salvador","Pozo") );
   lista[1].Puede_Votar( 'S' );
   ...
   return 0;
}

Aquí, instanciamos dos objetos donde explícitamente indicamos los 
nombres y apellidos, pero la demás información es implícita en el 
constructor. Posteriormente, accedemos a cada objeto para modificar el 
valor de un dato en particular; en este caso es 'puede_votar'.

Por último, veo que algunos datos no son necesarios. Por ejemplo, 
guardas la fecha de nacimiento al igual que su edad. Esto no es 
necesario y de hecho puede ser peligroso. Aconsejo pedir y guardar la 
fecha de nacimiento. Puedes ofrecer dar la edad, pero podemos calcularla 
a partir de la fecha de nacimiento y la fecha actual.

Quizá sea mejor implementar otra clase para representar una fecha: día, 
mes, y año, para luego instanciar un objeto dentro de 'habitantes_dn'.

> Gracias.
> 
> PD: Lo de system("clear"); es que estoy en Linux.
> 

Lo suponía, pero quería comentar este matiz.


Espero que todo esto te sirva y te oriente.

Steven






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