This tutorial will teach you how to overload most of the operators available in C++, including arithmetic and comparison, in order to create a class that is able to calculate rational numbers.
Probably one of the most interesting features of object oriented programming is the possibility to overload operators. This allows you to create your own class that handles the +, –, * and all the other arithmetical operators. It also allows you to override comparison operators such as ==, < and <= as well. By being able to do all this, you can create your own data types, just like int and float is. One of these data types is the rational type, which we will be creating today. The class we’re creating is slightly incomplete since it’s missing a few operators, however it does contain the most important ones and from that point on it’s easy for someone to complete it with the remaning operators.
What if you would have to create a class that is able to add rational numbers such as 1/2 + 3/4? The qiuck and dirty way would be to create functions and then use them like this:
string strRational = RationalAdd(1, 2, 3, 4); // Add 1/2 to 3/4 and store the result in a string
Surely this can’t be the best you can do. So let’s overload some operators.
We begin with the includes and the std namespace:
#include
#include
using namespace std;
Every data type is really a class, so what we need to create first is a class:
class Rational
{
   private:
      int num;
      int den;
   public:
      // Accessor and mutator functions
      void setNumerator(int);
      void setDenominator(int);
      int getNumerator();
      int getDenominator();
      // Greatest common divisor, needed to simplify fractions
      int gcd();
      // Simplifies fractions
      void simplify();
      // Arithmetic operators
      Rational operator+(Rational);
      Rational operator-(Rational);
      Rational operator*(Rational);
      Rational operator/(Rational);
      // Comparison operators
      bool operator==(Rational);
      bool operator!=(Rational);
      bool operator>(Rational);
      bool operator<(Rational);
      bool operator>=(Rational);
      bool operator<=(Rational);
      // Unary operator
      Rational operator-();
};
This class has a whole lot of public functions and only two private members: num and den. Each instance of the Rational class represents a rational number, and num and den represent the numerator and denominator of that rational number. Now the first four functions are pretty easy to figure out, they set and retrieve the numerator and denominator of the rational number. Let’s see their definition here:
void Rational::setNumerator(int n)
{
   num = n;
}
Â
void Rational::setDenominator(int n)
{
   den = n;
}
Â
int Rational::getNumerator()
{
   return num;
}
Â
int Rational::getDenominator()
{
   return den;
}
The gcd() function finds the greatest common divisor and it will be the engine behind the simplify() function which will follow next:
// Greatest common divisor
int Rational::gcd()
{
   int a = num;
   int b = den;
   int tmp;
   // While b is not 0
   while (b)
   {
      tmp = b;
      b = a % b;
      a = tmp;
   }
   return a;
}
The simplify() function is extremely important, as it will allow us to simplify the rational number to its simplest form. If the number is 4/8 it will simplify it to 1/2. Otherwise, if we’d try to later compare 4/8 with 1/2 and see if they are equal, we’d get a false response, even though they are really equal. This way, by being able to simplify both numbers, we are making sure that if they are equal they will both have the same numerator and denominator. simplify() merely makes a call to the gcd() function and then divides both numerator and denominator by the number return from gcd().
// Simplifies the fraction
void Rational::simplify()
{
   // Get the greatest common divisor
   int gcdNum = gcd();
   // If there is a common divisor, we don’t want to divide by 0
   if(gcdNum != 0)
   {
      // Set the new numerator
      num = num / gcdNum;
      // Set the new denominator
      den = den / gcdNum;
   }
}
And now comes the most interesting part, implementing the arithmetic operators. They all take an object of type Rational (i.e. a rational number) and return an object of type Rational (i.e. a rational number.)
Rational Rational::operator+(Rational ratPassed)
{
   // Adding fractions
   Rational ratResult;
   ratResult.num = num * ratPassed.den + den * ratPassed.num;
   ratResult.den = den * ratPassed.den;
   return ratResult;
}
Â
Rational Rational::operator-(Rational ratPassed)
{
   // Subtracting fractions
   Rational ratResult;
   ratResult.num = num * ratPassed.den – den * ratPassed.num;
   ratResult.den = den * ratPassed.den;
   return ratResult;
}
Â
Rational Rational::operator*(Rational ratPassed)
{
   // Multiplying fractions
   Rational ratResult;
   ratResult.num = num * ratPassed.num;
   ratResult.den = den * ratPassed.den;
   return ratResult;
}
Â
Rational Rational::operator/(Rational ratPassed)
{
   // Dividing fractions
   Rational ratResult;
   ratResult.num = num * ratPassed.den;
   ratResult.den = den * ratPassed.num;
   return ratResult;
}
What these functions really do is to calculate two fractions using basic mathematical rules on how to add, subtract, multiply and divide. They have quite an interesting signature though – Rational Rational::operator+(Rational ratPassed) – one where you specify the operator that you want to define (such as +, -, *, /) preceeded by “operator” mark.
Let’s look at the addition operator:
Rational Rational::operator+(Rational ratPassed)
{
   // Adding fractions
   Rational ratResult;
   ratResult.num = num * ratPassed.den + den * ratPassed.num;
   ratResult.den = den * ratPassed.den;
   return ratResult;
}
Here’s an example that will make a call to that function:
Rational ratResult = rat1 + rat2;
In the function definition ratPassed is rat2, while the instantiated Rational class is rat1. Thus when we call ratPassed.num and ratPassed.den we refer to rat2, and when we call num and den we call the num and den of rat1.
Let’s see the functions of the comparison operators:
bool Rational::operator==(Rational ratPassed)
{
   // Simplify the first rational number
   simplify();
   // Simplify the second (passed) rational number
   ratPassed.simplify();
   return (ratPassed.num == num) && (ratPassed.den == den);
}
Â
bool Rational::operator!=(Rational ratPassed)
{
   // Simplify the first rational number
   simplify();
   // Simplify the second (passed) rational number
   ratPassed.simplify();
   return (ratPassed.num != num) && (ratPassed.den != den);
}
Â
bool Rational::operator>(Rational ratPassed)
{
   // Simplify the first rational number
   simplify();
   // Simplify the second (passed) rational number
   ratPassed.simplify();
   return (num * ratPassed.den) > (ratPassed.num * den);
}
Â
bool Rational::operator<(Rational ratPassed)
{
   // Simplify the first rational number
   simplify();
   // Simplify the second (passed) rational number
   ratPassed.simplify();
   return (num * ratPassed.den) < (ratPassed.num * den);
}
Â
bool Rational::operator>=(Rational ratPassed)
{
   // Simplify the first rational number
   simplify();
   // Simplify the second (passed) rational number
   ratPassed.simplify();
   return (num * ratPassed.den) >= (ratPassed.num * den);
}
Â
bool Rational::operator<=(Rational ratPassed)
{
   // Simplify the first rational number
   simplify();
   // Simplify the second (passed) rational number
   ratPassed.simplify();
   return (num * ratPassed.den) <= (ratPassed.num * den);
}
They’re simpler than the arithmetical functions because you just do comparisons in the function itself, and then return the result of that comparison. But before you do that, each fraction is simplified using the simplify() function.
There’s one type of function left that handles a unary operator:
Rational Rational::operator-()
{
   // Unary operator multiplies the denominator by -1
   Rational ratResult;
   ratResult.den = den * -1;
   return ratResult;
}
This operator is used as such:
Rational newRat = -oldRat;
All this will do is to convert a positive fraction to a negative fraction and a negative fraction to a positive fraction by multiplying its numerator and denominator by -1. But what’s the difference between this and the – (minus) operator that subtracts two fractions when it comes to the function prototype? Well, when subtracting two fractions you take the second fraction as a parameter, and that’s reflected in the function prototype. With the unary operator you only use one fraction, and you already have that as the instance of the object.
That’s pretty much it for this tutorial, from this point on hopefully it’s clear to you how to implement the remaining operators. If not, feel free to post a comment.
Following is the full source code for this application:
#include
#include
using namespace std;
Â
class Rational
{
   private:
      int num;
      int den;
   public:
      // Accessor and mutator functions
      void setNumerator(int);
      void setDenominator(int);
      int getNumerator();
      int getDenominator();
      // Greatest common divisor, needed to simplify fractions
      int gcd();
      // Simplifies fractions
      void simplify();
      // Arithmetic operators
      Rational operator+(Rational);
      Rational operator-(Rational);
      Rational operator*(Rational);
      Rational operator/(Rational);
      // Comparison operators
      bool operator==(Rational);
      bool operator!=(Rational);
      bool operator>(Rational);
      bool operator<(Rational);
      bool operator>=(Rational);
      bool operator<=(Rational);
      // Unary operator
      Rational operator-();
};
Â
int main()
{
   // Preparing the numerator of the first rational number
   int ratNum1 = 0;
   cout << “Enter the denominator of the first rational number: “;
   cin >> ratNum1;
Â
   // Preparing the denominator of the first rational number
   int ratDen1 = 0;
   cout << “Enter the numerator of the first rational number: “;
   cin >> ratDen1;
Â
   // Create our first rational number
   Rational rat1;
   rat1.setNumerator(ratNum1);
   rat1.setDenominator(ratDen1);
Â
   // Preparing the numerator of the second rational number
   int ratNum2 = 0;
   cout << “Enter the denominator of the second rational number: “;
   cin >> ratNum2;
Â
   // Preparing the denominator of the second rational number
   int ratDen2 = 0;
   cout << “Enter the numerator of the second rational number: “;
   cin >> ratDen2;
Â
   // Create our second rational number
   Rational rat2;
   rat2.setNumerator(ratNum2);
   rat2.setDenominator(ratDen2);
Â
   // Sample arithmetic operation
   Rational rat3 = rat1 + rat2;
   cout << rat1.getNumerator() << “/” << rat1.getDenominator() << ” + “;
   cout << rat2.getNumerator() << “/” << rat2.getDenominator();
   cout << ” = ” << rat3.getNumerator() << “/” << rat3.getDenominator() << endl;
Â
   // Sample simplification
   cout << “Simplified “ << rat3.getNumerator() << “/” << rat3.getDenominator() << ” is “;
   rat3.simplify();
   cout << rat3.getNumerator() << “/” << rat3.getDenominator() << endl;
Â
   // Sample comparison operation
   if(rat1 > rat2)
   {
      cout << rat1.getNumerator() << “/” << rat1.getDenominator() << ” is bigger than “ << rat2.getNumerator() << “/” << rat2.getDenominator() << endl;
   }
   else
   {
      cout << rat1.getNumerator() << “/” << rat1.getDenominator() << ” is NOT bigger than “ << rat2.getNumerator() << “/” << rat2.getDenominator() << endl;
   }
   system(“PAUSE”);
   return 0;
}
Â
void Rational::setNumerator(int n)
{
   num = n;
}
Â
void Rational::setDenominator(int n)
{
   den = n;
}
Â
int Rational::getNumerator()
{
   return num;
}
Â
int Rational::getDenominator()
{
   return den;
}
Â
// Greatest common divisor
int Rational::gcd()
{
   int a = num;
   int b = den;
   int tmp;
   // While b is not 0
   while (b)
   {
      tmp = b;
      b = a % b;
      a = tmp;
   }
   return a;
}
Â
// Simplifies the fraction
void Rational::simplify()
{
   // Get the greatest common divisor
   int gcdNum = gcd();
   // If there is a common divisor, we don’t want to divide by 0
   if(gcdNum != 0)
   {
      // Set the new numerator
      num = num / gcdNum;
      // Set the new denominator
      den = den / gcdNum;
   }
}
Â
Rational Rational::operator+(Rational ratPassed)
{
   // Adding fractions
   Rational ratResult;
   ratResult.num = num * ratPassed.den + den * ratPassed.num;
   ratResult.den = den * ratPassed.den;
   return ratResult;
}
Â
Rational Rational::operator-(Rational ratPassed)
{
   // Subtracting fractions
   Rational ratResult;
   ratResult.num = num * ratPassed.den – den * ratPassed.num;
   ratResult.den = den * ratPassed.den;
   return ratResult;
}
Â
Rational Rational::operator*(Rational ratPassed)
{
   // Multiplying fractions
   Rational ratResult;
   ratResult.num = num * ratPassed.num;
   ratResult.den = den * ratPassed.den;
   return ratResult;
}
Â
Rational Rational::operator/(Rational ratPassed)
{
   // Dividing fractions
   Rational ratResult;
   ratResult.num = num * ratPassed.den;
   ratResult.den = den * ratPassed.num;
   return ratResult;
}
Â
bool Rational::operator==(Rational ratPassed)
{
   // Simplify the first rational number
   simplify();
   // Simplify the second (passed) rational number
   ratPassed.simplify();
   return (ratPassed.num == num) && (ratPassed.den == den);
}
Â
bool Rational::operator!=(Rational ratPassed)
{
   // Simplify the first rational number
   simplify();
   // Simplify the second (passed) rational number
   ratPassed.simplify();
   return (ratPassed.num != num) && (ratPassed.den != den);
}
Â
bool Rational::operator>(Rational ratPassed)
{
   // Simplify the first rational number
   simplify();
   // Simplify the second (passed) rational number
   ratPassed.simplify();
   return (num * ratPassed.den) > (ratPassed.num * den);
}
Â
bool Rational::operator<(Rational ratPassed)
{
   // Simplify the first rational number
   simplify();
   // Simplify the second (passed) rational number
   ratPassed.simplify();
   return (num * ratPassed.den) < (ratPassed.num * den);
}
Â
bool Rational::operator>=(Rational ratPassed)
{
   // Simplify the first rational number
   simplify();
   // Simplify the second (passed) rational number
   ratPassed.simplify();
   return (num * ratPassed.den) >= (ratPassed.num * den);
}
Â
bool Rational::operator<=(Rational ratPassed)
{
   // Simplify the first rational number
   simplify();
   // Simplify the second (passed) rational number
   ratPassed.simplify();
   return (num * ratPassed.den) <= (ratPassed.num * den);
}
Â
Rational Rational::operator-()
{
   // Unary operator multiplies the denominator by -1
   Rational ratResult;
   ratResult.den = den * -1;
   return ratResult;
}