2012-04-08 4 views
5

Tôi đang cố gắng tự dạy mình C++, và tôi sẽ trải qua một bài tập cơ bản về các nhà xây dựng. Tôi có một chương trình mà là hành xử cách bất ngờ:C++: Khó khăn của người xây dựng

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 (một số hiện thực bỏ qua):

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

Khi tôi chạy điều này, hai báo cáo in đầu tiên xuất ra 1/31/2 như mong đợi, nhưng bản thứ ba in 0/1 thay vì 5/6. Từ các câu lệnh gỡ lỗi tôi có, tôi tạo 5/6 thông qua hàm tạo Fraction(int, int), nhưng vì một lý do nào đó nó được gọi với 0/1. Khi tôi xóa hàm tạo bản sao, mã sẽ in ra 5/6. Điều gì đang xảy ra ở đây, và làm thế nào tôi có thể sửa chữa nó mà không cần loại bỏ các nhà xây dựng sao chép?

+0

Quá nhiều mã chịu trách nhiệm về sự cố bị thiếu. Bạn có thể đăng phần còn lại của mã hoặc tạo một ví dụ hoàn chỉnh, có thể biên dịch được để chứng minh sự cố không? –

+1

Hey chỉ cần ra khỏi tò mò - mà trình biên dịch được bạn sử dụng cho điều này? Tôi quan tâm đến việc xem nó cho phép 'const' mất tích ở vị trí đầu tiên như thế nào. –

Trả lời

7

Chữ ký cho nhà xây dựng bản sao của bạn nên được

Fraction(const Fraction&); 

không

Fraction(Fraction&); 

Khi bạn làm return Fraction(...);, trình biên dịch có gọi Fraction(const Fraction&) vì phần được trả lại là tạm thời, nhưng vì bạn không định nghĩa nó, trình biên dịch của bạn làm cho một cái gì đó kỳ lạ xảy ra. Trình biên dịch của bạn hoạt động một cách kỳ lạ và cho phép bạn sử dụng hàm tạo mặc định bằng cách nào đó, khi nào nó sẽ phát sinh lỗi. Việc biên dịch mã của bạn dưới dạng gcc không hoạt động, bạn sẽ phải thực hiện sửa đổi mà tôi đã đề cập và sửa lỗi đó.

Ngoài ra, thực tế là trình biên dịch của bạn không sử dụng RVO trên hàm đó gợi ý rằng bạn đang sử dụng trình biên dịch rất cũ và/hoặc sucky.

+0

+1 Tôi thứ hai, đây chắc chắn là câu trả lời. –

+0

Cảm ơn! Thêm 'const' làm cho nó hoạt động. – user1320895

+3

Xin chào @ user1320895, tôi thấy bạn mới sử dụng StackOverflow. Vì bạn chắc chắn đây là câu trả lời chính xác, hãy chắc chắn bạn nhấn dấu kiểm "chấp nhận" trên câu trả lời này, đó là nghi thức quanh đây. (Tôi được phép làm người nhắc nhở bạn vì tôi không đăng câu trả lời thực sự :-)). –