2016-02-24 25 views
3

我正在爲一個有理數的類實現一個類,這當然涉及覆蓋像'=='和'!='這樣的常見操作符。我很確定在我失蹤的地方有一個愚蠢的錯誤,不要猶豫,要求提供任何我沒有提供的文件。謝謝!C++:重寫操作符時的多重定義

rational.hpp:

#ifndef RATIONAL_HPP 
#define RATIONAL_HPP 

#include "test.hpp" 

#include <cstdlib> 
#include <iosfwd> 
#include <iostream> 
#include <assert.h> 

// Mathematical helper functions. 
// 
// NOTE: These are defined in rational.cpp. 
int gcd(int, int); 
int lcm(int, int); 


// Represents a rational number. The rational numbers are the set of 
// numbers that can be represented as the quotient of two integers. 
struct Rational 
{ 
    // TODO: Define the following: 
    // 1. A default constructor 
    int n; 
    int d; 
    Rational() 
    :n(0), d(1) {} 

    // 2. A constructor that takes an integer value 
    Rational(int num) 
    :n(num), d(1){} 
    // 3. A constructor that takes a pair of values 
    Rational(int numer, int denom) 
    :n(numer), d(denom) { 
    assert(d != 0); 
     int gcdnum; 
     if ((numer % denom) != 0){ 
      //do nothing 
     }else{ 
      gcdnum = gcd(numer, denom); 
      numer /= gcdnum; 
      denom /= gcdnum; 
      Rational(numer, denom); 
     } 
    } 
    // Returns the numerator. 
    int num() const { 
    return n; 
} 

    // Returns the denominator 
    int den() const { 
    return d; 
} 

}; 


bool operator==(Rational a, Rational b){ 
     return (a.n == b.n && a.d == b.d); 
} 
bool operator!=(Rational a, Rational b){ 
     return (a.n != b.n && a.d != b.d); 
} 
bool operator < (Rational a, Rational b){ 
     int lcdNum = lcm(a.d, b.d); 
     int newAN, newBN; //allows for comparisons without altering actuial value 
     newAN = a.n * lcdNum; 
     newBN = b.n * lcdNum; 
     return newAN < newBN; 
} 
bool operator > (Rational a, Rational b){ 
     int lcdNum = lcm(a.d, b.d); 
     int newAN, newBN; //allows for comparisons without altering actuial value 
     newAN = a.n * lcdNum; 
     newBN = b.n * lcdNum; 
     return newAN > newBN; 
} 
bool operator <= (Rational a, Rational b){ 
     int lcdNum = lcm(a.d, b.d); 
     int newAN, newBN; //allows for comparisons without altering actuial value 
     newAN = a.n * lcdNum; 
     newBN = b.n * lcdNum; 
     return newAN <= newBN; 
} 

bool operator >= (Rational a, Rational b){ 
     int lcdNum = lcm(a.d, b.d); 
     int newAN, newBN; //allows for comparisons without altering actuial value 
     newAN = a.n * lcdNum; 
     newBN = b.n * lcdNum; 
     return newAN >= newBN; 
} 

// 3. The standard arithmetic operators 
// - r1 + r2 
// - r1 - r2 
// - r1 * r2 
// - r1/r2 
// - r1/r2 
Rational operator + (Rational a, Rational b){ 
    int lcdNum = lcm(a.d, b.d); 
    int newAN, newBN; //allows for comparisons without altering actuial value 
    newAN = a.n * lcdNum; 
    newBN = b.n * lcdNum; 
    Rational c((newAN + newBN), (a.d * lcdNum)); 
    return c; 
} 
Rational operator - (Rational a, Rational b){ 
    int lcdNum = lcm(a.d, b.d); 
    int newAN, newBN; //allows for comparisons without altering actuial value 
    newAN = a.n * lcdNum; 
    newBN = b.n * lcdNum; 
    Rational c((newAN + newBN), (a.d * lcdNum)); 
    return c; 
} 
Rational operator * (Rational a, Rational b){ 
    Rational c((a.n * b.n), (a.d * b.d)); 
    return c; 
} 
Rational operator/(Rational a, Rational b){ 
    Rational c((a.n * b.d), (a.d * b.n)); //multiplies by the reciprocal 
    return c; 
} 


std::ostream& operator<<(std::ostream&, Rational); 
std::istream& operator>>(std::istream&, Rational&); 


#endif 

rational.cpp:

// 
// rational.hpp: Definition of rational class and its interace. 

#include "rational.hpp" 

#include <iostream> 


// -------------------------------------------------------------------------- // 
// Helper functions 

// Compute the GCD of two integer values using Euclid's algorithm. 
int 
gcd(int a, int b) 
{ 
    while (b != 0) { 
    int t = b; 
    b = a % b; 
    a = t; 
    } 
    return a; 
} 


// Compute the LCM of two integer values. 
int 
lcm(int a, int b) 
{ 
    return (std::abs(a)/gcd(a, b)) * std::abs(b); 
} 


// -------------------------------------------------------------------------- // 
// Rational implementation 


// TODO: Make this print integers when the denominator is 1. 
std::ostream& 
operator<<(std::ostream& os, Rational r) 
{ 
    if(r.den() == 1){ 
    return os << r.num(); 
}else{ 
    return os << r.num() << '/' << r.den(); 
} 
} 


// TODO: Make this read integer values if no '/' is given as a separator. 
// You may assume that there is no space between the numerator and the 
// slash. Hint, find and read the reference documentation for istream::peek(). 
std::istream& 
operator>>(std::istream& is, Rational& r) 
{ 
    int p, q; 
    char c; 
    is >> p; 
    c = is.peek(); 
    if (c == '/'){ 
    is >> c >> q; 
    if (!is) 
     return is; 

    // Require that the divider to be a '/'. 
    if (c != '/') { 
     is.setstate(std::ios::failbit); 
     return is; 
    } 

    // Make sure that we didn't read p/0. 
    if (q == 0) { 
     is.setstate(std::ios::failbit); 
     return is; 
    } 

    r = Rational(p, q); 
    return is; 
    }else{ 
    is.setstate(std::ios::failbit); 
} 
} 

rc.cpp:

// main.cpp: rational number test suite 

#include "rational.hpp" 

#include <iostream> 
#include <iomanip> 

#include <unistd.h> 


int 
main() 
{ 
    // Determine if input is coming from a terminal. 
    bool term = isatty(0); 

    // This will continue reading until it reaches the end-of-input. 
    // If you are using this interactivly, type crtl-d to send the 
    // end of input character to the terminal. 
    while (std::cin) { 
    Rational r1; 
    Rational r2; 
    std::string op; 

    if (term) 
     std::cout << "> "; 

    std::cin >> r1 >> op >> r2; 
    if (!std::cin) 
     break; 

    // FIXME: Add all of the other overlaoded operators by adding 
    // cases for each of them. 
    if (op == "==") 


    std::cout << std::boolalpha << (r1 == r2) << '\n'; 
    else if (op == "!=") 
    std::cout << std::boolalpha << (r1 != r2) << '\n'; 
    else if (op == "<") 
    std::cout << std::boolalpha << (r1 < r2) << '\n'; 
    else if (op == ">") 
    std::cout << std::boolalpha << (r1 > r2) << '\n'; 
    else if (op == "<=") 
    std::cout << std::boolalpha << (r1 <= r2) << '\n'; 
    else if (op == ">=") 
    std::cout << std::boolalpha << (r1 >= r2) << '\n'; 
    else if (op == "+") 
    std::cout << (r1 + r2) << '\n'; 
    else if (op == "-") 
    std::cout << (r1 - r2) << '\n'; 
    else if (op == "*") 
    std::cout << (r1 * r2) << '\n'; 
    else if (op == "/") 
    std::cout << (r1/r2) << '\n'; 
    else 
    std::cerr << "invalid operator: " << op << '\n'; 

    } 

    // If we got to the end of the file without fatal errors, 
    // return success. 
    if (std::cin.eof()) 
    return 0; 

    // Otherwise, diagnose errors in input and exit with an error 
    // code. 
    if (std::cin.fail()) { 
    std::cerr << "input error\n"; 
    return 1; 
    } 

    return 0; 
} 
+0

你得到的錯誤是什麼?你能對這個問題更具體嗎? – 0x499602D2

回答

3

每個翻譯單元#include您的rational.hpp將獲得比較運算符函數的定義,這肯定會在鏈接時導致重複的定義。

嘗試在他們面前粘貼一個「內嵌」關鍵字。

+0

我正在閱讀關於包括警衛,它說它們被用來防止多種定義。現在,OP在他的代碼中包含了一名守衛,但這仍然是一個問題,爲什麼? –

+1

@templateboy在單個*單位翻譯單元中包含警衛防範*多重包含*。這個答案在多個*翻譯單元中討論*多重定義*。 –

+0

@NickyC謝謝。 –

2

你定義裏面rational.hpp功能,這意味着每一個翻譯單元包括rational.hpp將包含定義,並導致重複的def初始錯誤。

您應該將聲明和定義分配到頭文件和實現文件中。比如,

rational.hpp:

bool operator==(Rational a, Rational b); 
bool operator!=(Rational a, Rational b); 
... 

rational.cpp:

bool operator==(Rational a, Rational b){ 
     return (a.n == b.n && a.d == b.d); 
} 
bool operator!=(Rational a, Rational b){ 
     return (a.n != b.n && a.d != b.d); 
} 
... 

BTW:在operator!=的邏輯似乎是錯的,我想這可能是return (a.n != b.n || a.d != b.d);。無論如何,正如@NickyC所建議的那樣,最好將其實現爲return !(a == b);以避免重複。

+0

我認爲'(a.n!= b.n && a.d!= b.d)'是一個邏輯(數學)錯誤。它使'1/4'和'2/4'「不等於」。我們應該介意德摩根定律。我更喜歡用'=='來實現'!='。 –

+0

@NickyC好點。添加。 – songyuanyao

+0

我正在閱讀有關包括衛兵,它說,他們被用來防止多種定義。現在,OP在他的代碼中包含了一名守衛,但這仍然是一個問題,爲什麼? –