Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++: Multiple definitions when overriding operators

I am working on implementing a class for a rational number, which of course involves overriding common operators like '==' and '!='. I'm pretty sure there is a stupid mistake somewhere that I am missing, don't hesitate to ask for any file that I haven't provided. Thanks!

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;
}
like image 850
iambicSam Avatar asked Mar 13 '23 04:03

iambicSam


1 Answers

Every translation unit that #includes your rational.hpp is going to get the definition of the comparison operator functions, which will certainly result in duplicate definitions at link time.

Try sticking an "inline" keyword in front of them.

like image 130
Sam Varshavchik Avatar answered Mar 24 '23 22:03

Sam Varshavchik