Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: ianmorar03 en 6 Septiembre 2018, 10:10 am



Título: C++ PUNTEROS a clases POO
Publicado por: ianmorar03 en 6 Septiembre 2018, 10:10 am
Tengo un problema a la hora de hacer un programa:
Digamos que quiero insertar objetos dentro de una colección, y en el main, quiero hacer una copia de un objeto a otro, a la hora de cambiar los atributos del nuevo objeto(copia), se cambian los de la original, doy un ejemplo:
Código
  1. #include <iostream>
  2. using namespace std;
  3. class persona{
  4. private:
  5.    string nom;
  6.    string id;
  7. public:
  8.    persona(){
  9.        nom=" ";
  10.        id=" ";
  11.    }
  12.    persona(string n,string i){
  13.        nom = n;
  14.        id=i;
  15.    }
  16.    string getNom(){
  17.        return nom;
  18.    }
  19.    string getId(){
  20.        return id;
  21.    }
  22.    void setNom(string n){
  23.        nom=n;
  24.    }
  25.    void setId(string i){
  26.        id=i;
  27.    }
  28.    ~persona(){
  29.        nom=" ";
  30.        id=" ";
  31.    }
  32. };
  33. class coleccion{
  34. private:
  35.    persona **p;
  36.    int cantidad;
  37. public:
  38.    coleccion(){
  39.        p=new persona*[10];
  40.        cantidad=0;
  41.    }
  42.    void ingresarPersona(persona *pe){
  43.        p[cantidad]=pe;
  44.        cantidad++;
  45.    }
  46.    persona devuelve(int i){
  47.        return *p[i];
  48.    }
  49.    ~coleccion(){
  50.        for(int i=0;i<cantidad;i++){
  51.            delete persona[i];
  52.        }
  53.        delete[] persona;
  54.    }
  55.  
  56. };
  57.  
  58. int main(){
  59.    coleccion *c = new coleccion;
  60.    persona *p1 = new persona("JUAN","12345");
  61.    persona *p2 =new persona("PEDRO","45678");
  62.  
  63.    c->ingresarPersona(p1);
  64.    c->ingresarPersona(p2);
  65.  
  66.    cout<<c->devuelve(0).getNom()<<endl; //muestra por pantalla "JUAN"
  67.    cout<<c->devuelve(1).getNom()<<endl; //muestra por pantalla "PEDRO"
  68.  
  69.    persona *p3; //hago una tercera persona
  70.    *p3 = c->devuelve(0); //le asigno los valores de la p1 a la p3
  71.    c->insertarPersona(*p3);
  72.  
  73.    cout<<c->devuelve(2).getNom()<<endl; //muestra por pantalla "JUAN"
  74.  
  75.    c->devuelve(2).setNom("CAMBIO");
  76.  
  77.    //se supone que solo cambia el nombre de p3
  78.    //pero cambia tambien el valor de p1
  79.  
  80.    cout<<c->devuelve(0).getNom()<<endl; //muestra por pantalla "CAMBIO"
  81.  
  82.  
  83.    system("PAUSE");
  84.    return 0;
  85. };
  86.  
  87.  
  88.  

Cuando yo hago una copia del puntero, al cambiar los valores de la copia, cambian los de la original, como puedo solucionar este problema?
Espero me hayan entendido :D


Título: Re: C++ PUNTEROS a clases POO
Publicado por: CalgaryCorpus en 6 Septiembre 2018, 14:01 pm
Asi funcionan los punteros. Son guardadores de las direcciones de memoria de los objetos.
El operador * y el operador -> no hacen mas que visitar las direcciones de memoria, por lo que cuando haces una copia de los punteros, solo haces copia de las direcciones, no de los objetos.

Por la misma razon, cuando modificas usando el operador -> estas visitando el mismo objeto para los 2 punteros.

Tener 2 punteros apuntando al mismo objeto se llama "alias" y esto que te ocurre es indicador de lo que ya te he explicado.

Posible solucion: Crea un constructor de copia y usalo en vez de hacer una asignacion en las lineas 69 y 70.

EL constructor de copia es un nuevo constructor que recibe un objeto del mismo tipo que la clase que estas creando.

Finalmene, despues de implementar el constructor de copia y reemplazar esas 2 lineas, tu codigo se veria:

Código
  1. persona *p3 = new persona(c->devuelve(0));

Sin ningun otro cambio necesario, deberia funcionar.

Una convencion que no estas usando es nombrar las clases con mayuscula inicial, intenta seguirlo para hacer mas facil a otros leer tu codigo.


Título: Re: C++ PUNTEROS a clases POO
Publicado por: MAFUS en 6 Septiembre 2018, 14:51 pm
He intentado ejecutar tu código para ayudarte pero, aparte de la falta del constructor copia, faltan arreglar unos cuantos errores. No debería compilarte.

Para saber qué es y qué hace un constructor copia pásate por aquí: http://c.conclase.net/curso/?cap=029#P29_COPIA

Aunque he de decirte que, ya que tus objetos están instanciados mediante new, en vez de recibir una referencia en el argumento (que también deberías incluir este constructor), deberás recibir un puntero.


Título: Re: C++ PUNTEROS a clases POO
Publicado por: ianmorar03 en 6 Septiembre 2018, 17:55 pm
Voy a averiguar mas sobre un constructor de copia y vere si funciona
Las clases siempre las uso en mayúsculas, y este código ni siquiera se
si compila, lo hice lo mas rapido y sencillo para que me entendieran :P
El codigo original es mas complicado, y tiene mucho mas cosas gg

Pero muchas gracias de antemano a los 2, @MAFUS y @CalgaryCorpus ;-)


Título: Re: C++ PUNTEROS a clases POO
Publicado por: MAFUS en 6 Septiembre 2018, 18:25 pm
Desde mi ignorancia de C++ hice este código:

Código
  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. class persona {
  6. private:
  7.    string nom;
  8.    string id;
  9.  
  10. public:
  11.    persona(){
  12.        nom="";
  13.        id="";
  14.    }
  15.  
  16.    persona(string n, string i) : nom(n), id(i) {}
  17.  
  18.    persona(const persona &p) : nom(p.nom), id(p.id) {} // Este copia sirve para objetos en stack
  19.  
  20.    persona(const persona *p) : nom(p->nom), id(p->id) {} // Este copia sirve para objetos en heap
  21.  
  22.    string getNom() {
  23.        return nom;
  24.    }
  25.  
  26.    string getId(){
  27.        return id;
  28.    }
  29.  
  30.    void setNom(string n){
  31.        nom = n;
  32.    }
  33.  
  34.    void setId(string i){
  35.        id = i;
  36.    }
  37. };
  38.  
  39. class coleccion{
  40. private:
  41.    persona *p[10];
  42.    int cantidad;
  43.  
  44. public:
  45.    coleccion() {
  46.        cantidad=0;
  47.    }
  48.  
  49.    void ingresarPersona(persona *pe) {
  50.        if(cantidad<10) {
  51.            p[cantidad]=pe;
  52.            cantidad++;
  53.        }
  54.    }
  55.  
  56.    persona* devuelve(int i) {
  57.        return p[i];
  58.    }
  59.  
  60.    ~coleccion() {
  61.        for(int i=0; i<cantidad; i++){
  62.            delete p[i];
  63.        }
  64.    }
  65. };
  66.  
  67. int main() {
  68.    coleccion *c = new coleccion;
  69.    persona *p1 = new persona("JUAN","12345");
  70.    persona *p2 = new persona("PEDRO","45678");
  71.  
  72.    c->ingresarPersona(p1);
  73.    c->ingresarPersona(p2);
  74.  
  75.    for(int i=0; i<2; ++i)
  76.        cout<<"c->devuelve("<<i<<")->getNom() = "<<c->devuelve(i)->getNom()<<"\n";
  77.    cout<<endl;
  78.  
  79.    persona *p3;
  80.    p3 = new persona(c->devuelve(0));
  81.    c->ingresarPersona(p3);
  82.  
  83.    for(int i=0; i<3; ++i)
  84.        cout<<"c->devuelve("<<i<<")->getNom() = "<<c->devuelve(i)->getNom()<<"\n";
  85.    cout<<endl;
  86.  
  87.    c->devuelve(2)->setNom("CAMBIO");
  88.  
  89.    for(int i=0; i<3; ++i)
  90.        cout<<"c->devuelve("<<i<<")->getNom() = "<<c->devuelve(i)->getNom()<<"\n";
  91.    cout<<endl;
  92. }


Título: Re: C++ PUNTEROS a clases POO
Publicado por: ianmorar03 en 6 Septiembre 2018, 18:32 pm
Ahora que recuerdo, creo haber visto el constructor de copia
en clases y no estaba prestando atención jaja
Utilizare el de copia para dinamico, que estoy utilizando
Dinamicos en mi programa


Título: Re: C++ PUNTEROS a clases POO
Publicado por: Mr.Moonlight en 13 Septiembre 2018, 18:25 pm
Siempre que estés trabajando con una clase que use punteros , los más recomendable es crear siempre constructor de copia y sobrecargar el operador de asignación para evitar este tipo de problemas o al menos yo siempre lo entendí así  :P