Geekpedia Programming Tutorials






Overloading Operators: Creating a Rational Class

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.

On Sunday, September 9th 2007 at 10:34 PM
By Andrew Pociu (View Profile)
****-   (Rated 3.7 with 9 votes)
Contextual Ads
More C++ Resources
Advertisement
Rational Class: Overloading Operators

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;

}

Digg Digg It!     Del.icio.us Del.icio.us     Reddit Reddit     StumbleUpon StumbleIt     Newsvine Newsvine     Furl Furl     BlinkList BlinkList

Rate Rate this tutorial
Comment Current Comments
by ww on Saturday, October 13th 2007 at 11:24 PM

I am warning you: Save yourself from learning cr@p from this article. Buy the Effective C++ book instead, and learn how to make it the right way.

If you learn from this article, you will learn how NOT to do it.

These
// 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);
must not be member functions.

The complete set of compound operators are missing.

Whoever wrote this article... well, he does not know C++ programming.

by newry on Saturday, November 17th 2007 at 02:20 AM

how come? the code looks fine to me and I've been using c++ for a good while now. it's not complete but the author mentioned that.

by Daniel on Saturday, March 1st 2008 at 01:11 PM

I agree, the article does exactly what it claims it intends to do - namely show how to overload operators. there may be other ways to define a rational class, but his ultimate goal was NOT to write the most effective class - it was merely to use a class definition to demonstrate overloaded operators.

I\'m recommending this article heartily!

by martzoo on Saturday, December 26th 2009 at 04:50 PM

simplify() function is not needed in <, >, >=, <= operators. (kind of "schematic" thinking of the author)
You can also code the == operator without simplify() function.
simplify() is needed rather to protect from accumulating high values in denominator and numerator and keep calculation precision.

by Rose on Tuesday, January 5th 2010 at 09:55 AM

hey guys. I'm a student of comsci in Philippines. can you please help me with these:

1. Write a rational number class. Problem will be revisited in Chapter 8, where operator overloading will make the problem much easier. For now, we will use member functions add, sub, mul, div, and less that each carry out the operations , -, *. /, and <. For example, a b will be written a. add (b), and a < b will be written a. less (b).

Define a class for rational numbers. A rational number is “ratio-nal” number, composed of two integers with division indicated. The division is not carried out; it is only indicated, as in ½, 2/3, 15/32, 65/4, 16/5. You should represent rational numbers by two int values, numerator and denominator.

A principle of abstract data type construction is that constructors must be present to create objects with legal values. You should provide constructors to make objects out of pairs of int values; this is a constructor with two int parameters. Since every int is also a rational no, 2/1 or 17/1, we should provide a constructor with single int parameter.



Provide member functions input and output that take an istream and ostream argument, respectively, and fetch or write rational no. in the form 2/3 or 37/51 to or from the keyboard (to or from a file).

And provide member functions add, sub, mul, and div that return a rational value. Provide a function less that returns a bool value. These functions should do the operations suggested by the name. Provide a member function neg that has no parameters or returns the negative of the calling object.
Provide a main function that thoroughly tests your class implementation. The ff formulas will be useful in defining functions:

a/b c/d = ( a*d b*c) / (b*d)
a/b - c/d = (a*d - b*c) / (b*d)
a/b * c/d = (a*c) (b*d)
a/b / c/d = (a*d) / (c*b)
-(a/b) = (-a/b)

(a/b) < (c/d) , means
(a*d) < (c*b)
(a/b) == (c/d), means
(a*d) == (c*d)


* Let any sign be carried by the numerator; keep the denominator positive.

Please. thank you. GOD bless us all. =)

by zeph on Saturday, January 9th 2010 at 01:23 AM

hey, we got the same programming problem! I'm trying to figure this one out but no luck... did you finish this one?

by zeph on Saturday, January 9th 2010 at 01:23 AM

hey, we got the same programming problem! I'm trying to figure this one out but no luck... did you finish this one?

by Rose on Saturday, January 9th 2010 at 02:59 AM

No, i have not gone to the middle of the prob. I hope they could teach us. I have codes but it doesn't work, you know.

by zeph on Sunday, January 10th 2010 at 03:31 AM

Yeah, me too... This code's working on my devcpp but it does not fullfll certain requirements of the peoblem... I'm having a hard time cracking my brain to figure how to make the codes...
I changes it a bit to conform to the requirements but a hell lot of errors appeared on my screen...

by Rose on Sunday, January 10th 2010 at 07:25 AM

Hope you find the right code. tomorrow's our last day to pass this requirement. ;) so, i just try to submit my own code which isn't wrkin too. LOL

by jennifer on Sunday, February 28th 2010 at 08:11 AM

this is quite an easy and interesting tutorial.it has helped me alot

by jennifer on Sunday, February 28th 2010 at 08:12 AM

this is quite an easy and interesting tutorial.it has helped me alot


Comment Comment on this tutorial
Name: Email:
Message:
Comment Related Tutorials
There are no related tutorials.

Comment Related Source Code
There is no related source code.

Jobs C++ Job Search
My skills include:
Enter a City:

Select a State:


Advanced Search >>
Advertisement

Free Magazine Subscriptions

Today's Pictures

Today's Video

Other Resources

Latest Download

Latest Icons