elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Introducción a Git (Primera Parte)


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  Problema al sobrecargar el operador +
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Problema al sobrecargar el operador +  (Leído 3,959 veces)
cNoob

Desconectado Desconectado

Mensajes: 59



Ver Perfil
Problema al sobrecargar el operador +
« en: 18 Diciembre 2017, 20:07 pm »

Ya se por que sucede el error que se muestra en este post, pero ahora el problema es otro (se dice en mi respuesta al mismo) no hace falta leer el código del programa para saber cual es mi duda. Por favor leed mi respuesta en el hilo para poder ayudarme, gracias.

Hola, he creado el siguiente programa para manejar y operar polinomios, consta de una clase llamada termino (c*x^e) y una clase llamada polinomio que es básicamente un array de términos y sus correspondientes operaciones, así como un método para mostrar el polinomio por pantalla. El codigo es algo largo pero el problema está principalmente en el método operator+, el cual si pido que muestre por pantalla el resultado (antes del return) el polinomio es correcto, pero una vez que lo devuelve y lo asigna a otro objeto polinomio y hago que este ultimo se muestre por pantalla es incorrecto (espero haberme hecho entender). Aquí os dejo el codigo:

main.cpp
Código
  1. #include <iostream>
  2. #include "CPolinomio.h"
  3.  
  4. using namespace std;
  5.  
  6. int main()
  7. {
  8.    CPolinomio p1(5,7);
  9.    CPolinomio p2(3,6);
  10.    CPolinomio p3;
  11.  
  12.    p1.asignarTermino(4,5);
  13.    p1.asignarTermino(10,3);
  14.    p2.asignarTermino(4,3);
  15.    p2.asignarTermino(5,5);
  16.    p2.mostrarPolinomio(); cout << " + ";
  17.    p1.mostrarPolinomio(); cout << endl;
  18.    p3 = p1 + p2; cout << endl;
  19.    (p1 + p2).mostrarPolinomio(); cout << endl;
  20.    p2.mostrarPolinomio();
  21.    //p2 = p1 + p1 + p1;
  22.    //p2.mostrarPolinomio();
  23.    //(p1+p1).mostrarPolinomio();
  24.  
  25.    return 0;
  26. }
  27.  

CTermino.h
Código
  1. #ifndef CTERMINO_H
  2. #define CTERMINO_H
  3.  
  4.  
  5. class CTermino
  6. //Cada uno de los terminos del polinomio
  7. {
  8. private:
  9.    double coeficiente;
  10.    int exponente;
  11. public:
  12.    CTermino(double = 0, int = 0);
  13.    void asignarCoeficiente (double);
  14.    void asignarExponente (int);
  15.    double obtenerCoeficiente (void) const;
  16.    int obtenerExponente (void) const;
  17.    void mostrar(void) const;
  18. };
  19.  
  20. #endif // CTERMINO_H
  21.  

CTermino.cpp
Código
  1. #include "CTermino.h"
  2. #include <iostream>
  3.  
  4. CTermino::CTermino(double c, int e) :
  5. coeficiente(c), exponente(e)
  6. {
  7.    if(e < 0){exponente = -e;}
  8. }
  9.  
  10. void CTermino::asignarCoeficiente (double c) {coeficiente = c;}
  11.  
  12. void CTermino::asignarExponente (int e)
  13. {
  14.    if(e < 0){exponente = -e;}
  15.    else{exponente = e;}
  16. }
  17.  
  18. double CTermino::obtenerCoeficiente (void) const {return coeficiente;}
  19.  
  20. int CTermino::obtenerExponente (void) const {return exponente;}
  21.  
  22. void CTermino::mostrar(void) const//es muy enrrevesado para mostrar los terminos como se suele hacer en algebra...
  23. {
  24.    if(!(coeficiente >= 0)){std::cout << " ";}
  25.    if(coeficiente > 0) std::cout << " +";
  26.    if(coeficiente != 1 && coeficiente != -1) {std::cout << coeficiente;}
  27.    if(coeficiente == -1 && exponente == 1) std::cout << "-";
  28.    if(exponente > 0)
  29.    {
  30.        if(exponente == 1) std::cout << "x";
  31.        else std::cout << "x^" << exponente;
  32.    }
  33. }

CPolinomio.h
Código
  1. #ifndef CPOLINOMIO_H
  2. #define CPOLINOMIO_H
  3. #include "CTermino.h"
  4.  
  5.  
  6. class CPolinomio
  7. {
  8. private:
  9.    CTermino* termino;
  10.    int grado;
  11.    void crearPolinomio (int);
  12.    void ampliar (int);
  13. public:
  14.    CPolinomio(double = 0,int = 0);
  15.    ~CPolinomio();
  16.    int obtenerGrado (void) const;
  17.    void asignarTermino (double , int);
  18.    void mostrarPolinomio(void) const;
  19.    const CPolinomio operator=(const CPolinomio&);
  20.    const CPolinomio operator+(const CPolinomio&) const;
  21.    const CPolinomio operator*(const CPolinomio&) const;
  22. };
  23.  
  24. #endif // CPOLINOMIO_H
  25.  

CPolinomio.cpp
Código
  1. #include "CPolinomio.h"
  2. #include <iostream>
  3.  
  4. CPolinomio::CPolinomio(double c, int e)//Constructor que crea la matriz de terminos del tamaño necesario
  5. {
  6.    grado = e; if(e < 0) {grado = -e;}//si el exponente es negativo lo cambia
  7.    crearPolinomio(e);
  8.    termino[e].asignarCoeficiente(c);//asigna el coeficiente al exponente correcto
  9. }
  10.  
  11. void CPolinomio::crearPolinomio(int g)//crea la matriz de objetos termino del tamaño necesario
  12. {
  13.    delete [] termino; termino = new CTermino [g+1];
  14.    for (int i = 0; i <= g; i++) termino[i].asignarExponente(i);
  15. }
  16.  
  17. void CPolinomio::ampliar (int g)//amplia la matriz terminos al tamaño pasado por parametro
  18. {
  19.    double coeficientes [grado+1];
  20.    for(int i = 0; i <= grado; i++) coeficientes [i] = termino[i].obtenerCoeficiente();//copia los terminos en una matriz
  21.    crearPolinomio(g);
  22.    for (int i = 0; i <= grado; i++) termino[i].asignarCoeficiente(coeficientes [i]);//copia los terminos de vuelta al nuevo array
  23.    grado = g;
  24. }
  25.  
  26. CPolinomio::~CPolinomio()
  27. {
  28.    delete [] termino;
  29. }
  30.  
  31. int CPolinomio::obtenerGrado(void) const {return grado;}
  32.  
  33. void CPolinomio::asignarTermino(double c, int e)
  34. {
  35.    if(e < 0) return;//SI NO ES VALIDO NO HACE NADA
  36.    if(e > grado)//SI EL EXPONENTE ES MAYOR QUE EL GRADO CREA UN NUEVO POLINOMIO ADECUADO
  37.    {
  38.        ampliar(e);
  39.        termino[e].asignarCoeficiente(c);
  40.    }
  41.    else {
  42.        termino[e].asignarCoeficiente(c);//SI TODO ES NORMAL SIMPLEMENTE LO CAMBIA
  43.    }
  44. }
  45.  
  46. void CPolinomio::mostrarPolinomio(void) const//funcion que muestra el polinomio
  47. {
  48.    std::cout << "(";
  49.    for(int i = grado; i > 0; i--) {if(termino[i].obtenerCoeficiente() != 0)termino[i].mostrar();}
  50.    if(termino[0].obtenerCoeficiente() != 0) termino[0].mostrar();
  51.    std::cout << ")";
  52. }
  53.  
  54. const CPolinomio CPolinomio::operator=(const CPolinomio& pol)//operador =
  55. {
  56.    grado = pol.grado;
  57.    ampliar(pol.grado);
  58.    for(int i = 0; i <= pol.grado; i++) termino[i].asignarCoeficiente(pol.termino[i].obtenerCoeficiente());
  59. }
  60.  
  61. const CPolinomio CPolinomio::operator+(const CPolinomio& pol) const//operador +
  62. {
  63.  
  64.    if(grado == pol.grado)//si ambos grados son iguales (no hay que ampliar)
  65.    {
  66.        CPolinomio resultado(0, grado);
  67.        for(int i = 0; i <= resultado.grado; i++)
  68.        {
  69.            resultado.termino[i].asignarCoeficiente(pol.termino[i].obtenerCoeficiente() + termino[i].obtenerCoeficiente());
  70.        }
  71.        resultado.mostrarPolinomio();//codigo experimental para saber si el error es al devolver el objeto
  72.        return resultado;
  73.    }
  74.    else {
  75.        if(grado > pol.grado)//si uno de los polinomios tiene mas grado
  76.        {
  77.            CPolinomio resultado(0, grado);
  78.            for(int i = 0; i <= pol.grado; i++)
  79.            {
  80.                resultado.termino[i].asignarCoeficiente(pol.termino[i].obtenerCoeficiente() + termino[i].obtenerCoeficiente());
  81.            }
  82.            for(int i = pol.grado+1; i <= grado; i++) resultado.termino[i].asignarCoeficiente(termino[i].obtenerCoeficiente());
  83.            resultado.mostrarPolinomio();//codigo experimental para saber si el error es al devolver el objeto
  84.            return resultado;
  85.        }
  86.        if(grado < pol.grado)//si el otro polinomio es mayor
  87.        {
  88.            CPolinomio resultado(0, pol.grado);
  89.            for(int i = 0; i <= grado; i++)
  90.            {
  91.                resultado.termino[i].asignarCoeficiente(pol.termino[i].obtenerCoeficiente() + termino[i].obtenerCoeficiente());
  92.            }
  93.            for(int i = grado+1; i <= pol.grado; i++) resultado.termino[i].asignarCoeficiente(pol.termino[i].obtenerCoeficiente());
  94.            resultado.mostrarPolinomio();//codigo experimental para saber si el error es al devolver el objeto
  95.            return resultado;
  96.        }
  97.    }
  98. }
  99.  
  100. const CPolinomio CPolinomio::operator*(const CPolinomio& pol) const//operador *
  101. {
  102.    int gr = pol.grado*grado;
  103.    CPolinomio resultado(gr);
  104.  
  105.    for (int i = 0; i <= grado; i++)
  106.    {
  107.        if(termino[i].obtenerExponente() != 0)
  108.        {
  109.            CPolinomio calculos;
  110.            for(int x = 0; x <= pol.grado; x++)
  111.            {
  112.                calculos.asignarTermino(termino[i].obtenerCoeficiente() * pol.termino[x].obtenerCoeficiente(), termino[i].obtenerExponente() + pol.termino[x].obtenerExponente());
  113.            }
  114.            resultado = resultado + calculos;
  115.        }
  116.    }
  117.  
  118.    return resultado;
  119. }

Cuando lo ejecuto se muestra lo siguiente:

( +3x^6 +5x^5 +4x^3) + ( +5x^7 +4x^5 +10x^3)
( +5x^7 +3x^6 +9x^5 +14x^3)
( +5x^7 +3x^6 +9x^5 +14x^3)( +5x^1981370576 +9.88131e-324)
( +3x^6 +5x^5 +4x^3)
Process returned 0 (0x0)   execution time : 0.111 s
Press any key to continue.


Espero que alguien sepa que puede ser, sospecho que estoy retornando el objeto resultado de operator+ mal...


« Última modificación: 19 Diciembre 2017, 17:22 pm por cNoob » En línea

Wannabe programador autodidacta de c++
"Usain Bolt comenzó gateando."
CalgaryCorpus


Desconectado Desconectado

Mensajes: 323


Ver Perfil WWW
Re: Problema al sobrecargar el operador +
« Respuesta #1 en: 19 Diciembre 2017, 00:21 am »

Sugiero que escribas tu propio constructor por default en la clase Polinomio, y que no ejecutes el que por default hace nada. De esta manera, en el main, cuando p3 es construido, sabes exactamente lo que se esta construyendo y no descansas en comportamientos automaticos provistos por el compilador.


En línea

Aqui mi perfil en LinkedIn, invitame un cafe aqui
cNoob

Desconectado Desconectado

Mensajes: 59



Ver Perfil
Re: Problema al sobrecargar el operador +
« Respuesta #2 en: 19 Diciembre 2017, 14:44 pm »

De esta manera, en el main, cuando p3 es construido, sabes exactamente lo que se esta construyendo y no descansas en comportamientos automáticos provistos por el compilador.
En el constructor de la clase polinomio automáticamente se asigna el valor 0 al coeficiente de cada termino y su valor correspondiente al exponente (a no ser que se pase un coeficiente a un termino en los parámetros a la hora de crear el polinomio) por lo que esos "valores basura" que supongo que vienen de espacios de memoria no asignados no deberían de estar ahí
En línea

Wannabe programador autodidacta de c++
"Usain Bolt comenzó gateando."
cNoob

Desconectado Desconectado

Mensajes: 59



Ver Perfil
Re: Problema al sobrecargar el operador +
« Respuesta #3 en: 19 Diciembre 2017, 16:01 pm »

Vale, he descubierto que pasa, cuando el operador devuelve el objeto "resultado" el atributo "termino" es devuelto también y el destructor de la clase borra la memoria donde estaba el array con los términos, por lo que estos no son copiados como deberían por el operador = (si se elimina el destructor el programa funciona perfectamente, pero este es necesario para vaciar la memoria reservada por el operador new).
Mi pregunta ahora es: ¿como puedo hacer que primero se copien los términos y que cuando esta operación finalice se ejecute el destructor del objeto resultado?
En línea

Wannabe programador autodidacta de c++
"Usain Bolt comenzó gateando."
CalgaryCorpus


Desconectado Desconectado

Mensajes: 323


Ver Perfil WWW
Re: Problema al sobrecargar el operador +
« Respuesta #4 en: 19 Diciembre 2017, 17:56 pm »

Crea un constructor de copia
En línea

Aqui mi perfil en LinkedIn, invitame un cafe aqui
cNoob

Desconectado Desconectado

Mensajes: 59



Ver Perfil
Re: Problema al sobrecargar el operador +
« Respuesta #5 en: 19 Diciembre 2017, 18:24 pm »

Crea un constructor de copia
Por qué un constructor copia solucionaría el problema?
En línea

Wannabe programador autodidacta de c++
"Usain Bolt comenzó gateando."
cNoob

Desconectado Desconectado

Mensajes: 59



Ver Perfil
Re: Problema al sobrecargar el operador +
« Respuesta #6 en: 19 Diciembre 2017, 19:10 pm »

Crea un constructor de copia
Vale, acabo de escribir el siguiente constructor copia y el programa funciona perfectamente
Código
  1. CPolinomio::CPolinomio(const CPolinomio& P)
  2. {
  3.    grado = P.grado;
  4.    crearPolinomio(grado);
  5.    for (int i = 0; i <= grado; i++) termino[i] = P.termino[i];
  6. }
Todavía no se por que se necesita el constructor copia... (si alguien puede explicármelo por favor) muchas gracias por la ayuda :D
En línea

Wannabe programador autodidacta de c++
"Usain Bolt comenzó gateando."
CalgaryCorpus


Desconectado Desconectado

Mensajes: 323


Ver Perfil WWW
Re: Problema al sobrecargar el operador +
« Respuesta #7 en: 19 Diciembre 2017, 21:17 pm »

Las variables locales se mueren o deberian morirse al terminar el bloque donde estan. El polinomio que aparece al lado derecho del operador = es una copia de la variable local que se murio. Si no tienes constructor de copia, entonces uno default se provee que hace copias sin mucha inteligencia, en particular con los punteros, generando alias.
2 objetos con punteros a los mismos datos, solo que uno de ellos los destruye y deja al otro apuntando al limbo.

Solucion? Constructor de copia que puede hacer copias mas inteligentes, en particular con los punteros haciendo que cada objeto apunte a su propia copia de datos y entonces da lo mismo si el objeto original se muere y destruye los datos, porque antes de hacerlo el otro objeto copio y dejo su propio puntero apuntando a su propia copia.


« Última modificación: 19 Diciembre 2017, 21:22 pm por CalgaryCorpus » En línea

Aqui mi perfil en LinkedIn, invitame un cafe aqui
cNoob

Desconectado Desconectado

Mensajes: 59



Ver Perfil
Re: Problema al sobrecargar el operador +
« Respuesta #8 en: 20 Diciembre 2017, 15:24 pm »

Oh, entiendo... supuse que el compilador haría uso del operador de asignación para pasar los datos de un objeto al otro, pero ahora ya se que no. Gracias   ;D
En línea

Wannabe programador autodidacta de c++
"Usain Bolt comenzó gateando."
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines