2012-04-08 11 views
5

Sto cercando di insegnare a me stesso C++ e sto passando un esercizio di base sui costruttori. Ho un programma che si comporta inaspettatamente:C++: problemi di costruzione

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 (alcune implementazioni omessi):

#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; 
} 

Quando eseguo questa operazione, le prime due istruzioni di stampa restituiscono 1/3 e 1/2 come previsto, ma il terzo stampa 0/1 anziché 5/6. Dalle dichiarazioni di debug che ho creato 5/6 tramite il costruttore Fraction(int, int), ma per qualche motivo viene chiamato con 0/1. Quando rimuovo il costruttore di copie, il codice viene stampato 5/6. Cosa sta succedendo qui e come posso risolverlo senza rimuovere il costruttore di copie?

+0

Manca troppo il codice responsabile del problema. Puoi postare il resto del codice o creare un esempio completo e compilabile che mostri il problema? –

+1

Ehi solo per curiosità - quale compilatore stavi usando per questo? Sono interessato a vedere come ha permesso la mancanza di 'const' in primo luogo. –

risposta

7

La firma per il vostro costruttore di copia dovrebbe essere

Fraction(const Fraction&); 

non

Fraction(Fraction&); 

Quando si esegue return Fraction(...);, il compilatore deve chiamare Fraction(const Fraction&) perché la frazione viene restituito è un temporaneo, ma dal momento che non lo definisci, il tuo compilatore fa accadere qualcosa di strano. Il compilatore si comporta in modo strano e consente di utilizzare il costruttore predefinito in qualche modo, quando dovrebbe dare un errore. Compilare il tuo codice così com'è su gcc non funziona, dovrai apportare la modifica che ho menzionato e che dovrebbe risolverlo.

Inoltre, il fatto che il compilatore non utilizzi RVO su tale funzione suggerisce che si sta utilizzando un compilatore molto vecchio e/o sucky.

+0

+1 Secondo, questa è sicuramente la risposta. –

+0

Grazie! L'aggiunta di 'const' ha funzionato. – user1320895

+3

Ciao @ user1320895, vedo che sei nuovo su StackOverflow. Dato che sei sicuro che questa sia la risposta corretta, assicurati di premere il segno di spunta "Accetto" su questa risposta, cioè l'etichetta qui intorno. (Mi è permesso essere il ragazzo che ti ricorda dato che non ho postato la risposta effettiva :-)). –