2012-04-08 21 views
5

Estoy tratando de enseñarme C++, y estoy realizando un ejercicio básico sobre constructores. Tengo un programa que se comporta de forma inesperada:C++: Problemas de constructor

Fraction.h:

#include <iostream> 

#ifndef FRACTION_H 
#define FRACTION_H 

using namespace std; 

class Fraction 
{ 
private: 
    int num; 
    int denom; 
    static int gcd(int a, int b); 
    void reduce(); 
public: 
    Fraction(int n=0, int d=1); 
    Fraction(Fraction& f); 
    ~Fraction(); 

    Fraction& operator=(const Fraction& f); 

    friend Fraction operator+(const Fraction& f1, const Fraction& f2); 

    friend ostream& operator<<(ostream& out, const Fraction& f); 
}; 

#endif // FRACTION_H 

Fraction.cpp (algunas implementaciones omitidas):

#include "../include/Fraction.h" 

#include <cassert> 
#include <iostream> 

using namespace std; 

int Fraction::gcd(int a, int b) { 
    // implementation omitted 
} 

void Fraction::reduce() { 
    // implementation omitted 
    // this just reduces fractions to lowest terms, like 3/6 to 1/2 
} 

Fraction::Fraction(int n, int d) { 
    cout << "new fraction, n=" << n << ", d=" << d << endl; 
    assert(d != 0); 
    if (d < 0) { 
     num = -n; 
     denom = -d; 
    } else { 
     num = n; 
     denom = d; 
    } 
    reduce(); 
} 

Fraction::Fraction(Fraction& f) { 
    cout << "copy fraction " << f << " at " << &f << endl; 
    num = f.num; 
    denom = f.denom; 
} 

Fraction::~Fraction() { 
} 

Fraction& Fraction::operator=(const Fraction& f) { 
    cout << "assign fraction to " << f << " at " << &f << endl; 
    if (this == &f) 
     return *this; 
    num = f.num; 
    denom = f.denom; 
    return *this; 
} 

Fraction operator+(const Fraction& f1, const Fraction& f2) { 
    cout << "adding " << f1 << " and " << f2 << endl; 
    return Fraction(f1.num * f2.denom + f2.num * f1.denom, 
        f1.denom * f2.denom); 
} 

ostream& operator<<(ostream& out, const Fraction& f) { 
    out << f.num << "/" << f.denom; 
    return out; 
} 

main.cpp:

#include "include/Fraction.h" 

#include <iostream> 

using namespace std; 

int main() 
{ 
    Fraction f1(1, 3); 
    Fraction f2(1, 2); 
    cout << f1 << endl; 
    cout << f2 << endl; 
    cout << (f1 + f2) << endl; 
    return 0; 
} 

Cuando ejecuto esto, las primeras dos instrucciones de impresión dan como resultado 1/3 y 1/2 como se esperaba, pero el tercero imprime 0/1 en lugar de 5/6. De las declaraciones de depuración que tengo, creo 5/6 a través del constructor Fraction(int, int), pero por alguna razón se llama con 0/1. Cuando elimino el constructor de copia, el código se imprime 5/6. ¿Qué está pasando aquí, y cómo puedo solucionarlo sin eliminar el constructor de copia?

+0

Falta demasiada parte del código responsable del problema. ¿Puede publicar el resto del código o crear un ejemplo completo y compilable que demuestre el problema? –

+1

Hola por curiosidad, ¿qué compilador usaste para esto? Me interesa ver cómo permitió el 'const' desaparecido en primer lugar. –

Respuesta

7

La firma para su constructor de copia debe ser

Fraction(const Fraction&); 

no

Fraction(Fraction&); 

Al hacer return Fraction(...);, el compilador tiene que llamar Fraction(const Fraction&) porque la fracción que se devuelve es un temporal, pero ya que no lo defines, tu compilador hace que ocurra algo extraño. Su compilador se comporta de manera extraña y le permite usar el constructor predeterminado de alguna manera, cuando debería provocar un error. Compilar tu código tal como está en gcc no funciona, tendrás que hacer la modificación que mencioné y que debería arreglarlo.

Además, el hecho de que su compilador no esté utilizando RVO en esa función indica que está utilizando un compilador muy antiguo y/o sucky.

+0

+1 En segundo lugar, esta es definitivamente la respuesta. –

+0

¡Gracias! Agregar 'const' lo hizo funcionar. – user1320895

+3

Hola @ user1320895, veo que eres nuevo en StackOverflow. Como está seguro de que esta es la respuesta correcta, asegúrese de presionar la marca de verificación "aceptar" en esta respuesta, que es la etiqueta por aquí. (Se me permite ser el tipo que te recuerda ya que no publiqué la respuesta real :-)). –