2016-02-24 2 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, получит определение функций оператора сравнения, что, безусловно, приведет к дублированию определений во времени связи.

Попробуйте использовать ключевое слово "inline" перед ними.

+0

Я читал о включении охранников, и он сказал, что они используются для предотвращения множества определений. Теперь у ОП есть включенный охранник в его коде, но это как-то все еще проблема, почему? –

+1

@templateboy Включить защитные меры против * множественного включения * в единицу * перевода *. В этом ответе говорится о * множественном определении * через * несколько единиц перевода. –

+0

@NickyC спасибо. –

2

Вы определения функций внутри rational.hpp, что означает, что каждый блок перевода include 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); 
} 
... 

КСТАТИ: Логика в 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

Я читал о включении охранников, и он сказал, что они используются для предотвращения множества определений. Теперь у ОП есть включенный охранник в его коде, но это как-то все еще проблема, почему? –

Смежные вопросы