Example of overriding operators in C++ using a class that deals with fractions

C++ allows for the ability to overwrite operators. This program shows an example using various operators in a class that deals with fractions. It also throws a runtime exception if a divide by zero is attempted.

Running

Source Code

main.cpp

#include "fraction.h"

int main()
{

  Fraction a; // Value is 0/1
  Fraction b(4); // Value is 4/1
  Fraction c(6, 8); // Value is 6/8, which is converted to 3/4
  cout << "Constructed values " << a << " " << b << " " << c << "\n";
  cout << "Value of c is " << c.numerator() << "/" << c.denominator() << "\n";
  // Test arithmetic instructions
  Fraction d = b + c;
  cout << "4 + 3/4 is " << d << "\n";
  d = b - c;
  cout << "4 - 3/4 is " << d << "\n";
  Fraction e = (b + (-c));
  cout << e << " done with negation\n";
  if (d == e) cout << "Subtraction test successful\n";
  a = Fraction(6, 8);
  b = Fraction(7, 8);
  if (a < b) cout << "Compare successful\n";
  
  Fraction f(3, 0);
  
  return 0;
}

fraction.h

#ifndef FRACTION_H
#define FRACTION_H
#include <iostream>

using namespace std;

class Fraction
{
  public:
    Fraction();
    Fraction(int t);
    Fraction(int t, int b);
    int numerator() const;
    int denominator() const;
    Fraction& operator+=(const Fraction& right);
    Fraction& operator++();
    Fraction operator++(int unused);
    int compare(const Fraction& right) const;
  private:
    void normalize();
    int gcd(int n, int m);
    int top;
    int bottom;
};

Fraction operator+(const Fraction& left, const Fraction& right);
Fraction operator-(const Fraction& left, const Fraction& right);
Fraction operator*(const Fraction& left, const Fraction& right);
Fraction operator/(const Fraction& left, const Fraction& right);
Fraction operator-(const Fraction& value);
bool operator<(const Fraction& left, const Fraction& right);
bool operator<=(const Fraction& left, const Fraction& right);
bool operator==(const Fraction& left, const Fraction& right);
bool operator!=(const Fraction& left, const Fraction& right);
bool operator>=(const Fraction& left, const Fraction& right);
bool operator>(const Fraction& left, const Fraction& right);
ostream& operator<<(ostream& out, const Fraction& value);
istream& operator>>(istream& in, Fraction& r);

#endif

fraction.cpp

#include "fraction.h"
#include <cassert>
#include <stdexcept>

int Fraction::gcd(int n, int m)
{
  assert((n > 0) && (m > 0));
  while (n != m)
  {
    if (n < m)
      m = m - n;
    else
      n = n - m;
  }
  return n;
}

Fraction::Fraction(int t, int b) : top(t), bottom(b)
{
  if (b == 0) throw runtime_error("divide by zero exception thrown");
  normalize();
}

Fraction::Fraction() : top(0), bottom(1) {}

Fraction::Fraction(int t) : top(t), bottom(1) {}

int Fraction::numerator() const
{
  return top;
}

int Fraction::denominator() const
{
  return bottom;
}

void Fraction::normalize()
{
  int sign = 1;
  if (top < 0)
  {
    sign = -1;
    top = -top;
  }
  if (bottom < 0)
  {
    sign = -sign;
    bottom = -bottom;
  }
  assert(bottom != 0);
  int d = 1;
  if (top > 0) d = gcd(top, bottom);
  top = sign * (top / d);
  bottom = bottom / d;
}

Fraction operator+(const Fraction& left, const Fraction& right)
{
  Fraction result(left.numerator() * right.denominator()
    + right.numerator() * left.denominator(),
    left.denominator() * right.denominator());
  return result;
}

Fraction operator-(const Fraction& left, const Fraction& right)
{
  Fraction result(left.numerator() * right.denominator()
    - right.numerator() * left.denominator(),
    left.denominator() * right.denominator());
  return result;
}

Fraction operator*(const Fraction& left, const Fraction& right)
{
  Fraction result(left.numerator() * right.numerator(),
    left.denominator() * right.denominator());
  return result;
}

Fraction operator/(const Fraction& left, const Fraction& right)
{
  Fraction result(left.numerator() * right.denominator(),
    left.denominator() * right.numerator());
  return result;
}

Fraction operator-(const Fraction& value)
{
  Fraction result(-value.numerator(), value.denominator());
  return result;
}

int Fraction::compare(const Fraction& right) const
{
  return numerator() * right.denominator()
    - denominator() * right.numerator();
}

bool operator<(const Fraction& left, const Fraction& right)
{
  return left.compare(right) < 0;
}

bool operator<=(const Fraction& left, const Fraction& right)
{
  return left.compare(right) <= 0;
}

bool operator==(const Fraction& left, const Fraction& right)
{
  return left.compare(right) == 0;
}

bool operator!=(const Fraction& left, const Fraction& right)
{
  return left.compare(right) != 0;
}

bool operator>=(const Fraction& left, const Fraction& right)
{
  return left.compare(right) >= 0;
}

bool operator>(const Fraction& left, const Fraction& right)
{
  return left.compare(right) > 0;
}

ostream& operator<<(ostream& out, const Fraction& value)
{
  out << value.numerator() << "/" << value.denominator();
    return out;
}

istream& operator>>(istream& in, Fraction& r)
{
  int t, b;
  in >> t;
  char c;
  in >> c;
  if (c == '/')
  in >> b;
  else
  {
    in.unget();
    b = 1;
  }
  r = Fraction(t, b);
  return in;
}

Fraction& Fraction::operator++()
{
  top += bottom;
  return *this;
}

Fraction Fraction::operator++(int unused)
{
  Fraction clone(top, bottom);
  top += bottom;
  return clone;
}

Fraction& Fraction::operator+=(const Fraction& right)
{
  top = top * right.denominator() + bottom * right.numerator();
  bottom *= right.denominator();
  normalize();
  return *this;
}