Overloading Relational Operators (==, !=, <, <=, >, >=)


Overloading relational operators as standalone functions

The arithmetic operators may always be overloaded as standalone functions. For an operator that will take two objects of your new class as operands, the skeleton of the function definition should always look like this:

bool operator symbol(const ClassName& lhs, const ClassName& rhs)
{
    // Compare lhs and rhs and return either true or false accordingly
}

In the code skeleton above, items in red will need to be changed by the programmer - plug in the name of your class and the operator symbol you want to overload. Items in black are standard and generally don't change no matter what relational operator is being overloaded or what class the operator is overloaded for.

To see how this works in practice, let's look at a specific example.

Example 1: The == operator overloaded as a standalone friend function of the Rational class

To designate our overloaded operator function as a friend of the Rational class, we need to include the function's prototype, preceded by the keyword friend, anywhere in the declaration of the Rational class:

class Rational
{
    friend bool operator==(const Rational&, const Rational&);

private:
    int numerator,
        denominator;

public:
    .
    .
    .
};

The function definition can then be coded like so:

bool operator==(const Rational& lhs, const Rational& rhs)
{
    if (lhs.numerator == rhs.numerator && lhs.denominator == rhs.denominator)
        return true;
    else
        return false;
} 

Pretty easy! But actually, since the expression lhs.numerator == rhs.numerator && lhs.denominator == rhs.denominator will itself evaluate to true or false, it's possible to shorten the code a bit:

bool operator==(const Rational& lhs, const Rational& rhs)
{
    return (lhs.numerator == rhs.numerator && lhs.denominator == rhs.denominator);
} 

Once we’ve overloaded this operator as a standalone function, we can use it to compare two objects of the Rational class:

Rational r1(3, 5);     // Create r1 and set it = 3/5
Rational r2(2, 3);     // Create r2 and set it = 2/3

if (r1 == r2)          // Generates the function call if (operator==(r1, r2))
    cout << "equal\n";          

Overloading relational operators as member functions

If we overload a relational operator as a member function, the left operand will be passed implicitly and can be accessed using the this pointer. This means that a member function to overload a relational operator will take one argument rather than the usual two.

This also means that the left operand must be an object of our new class in order to overload the operator as a member function of our class. We can code an overloaded operator member function that takes two Rational objects as operands, or an overloaded operator member function that takes a Rational object as the left operand and an int as the right operand. If we want an overloaded operator function that takes an int as the left operand and a Rational object as the right operand, that function can not be implemented as a member function of the Rational class. It will need to be implemented as a standalone friend function instead.

The member function will not change the invoking object (the left operand), so it should made const.

Here’s a skeleton of the code for overloading a relational operator as a member function:

bool ClassName::operator symbol(const ClassName& rhs) const
{
    // Compare this and rhs and return either true or false accordingly
}

Once again, here's a specific example.

Example 2: The == operator overloaded as a member function of the Rational class

bool Rational::operator==(const Rational& rhs) const
{
    return (numerator == rhs.numerator && denominator == rhs.denominator);
}

Notice that the code here is extremely similar to the code for Example 1. There's also no difference in how the overloaded operator is used, although the actual call generated by the compiler is different:

Rational r1(3, 5);     // Create r1 and set it = 3/5
Rational r2(2, 3);     // Create r2 and set it = 2/3

if (r1 == r2)          // Generates the function call if (r1.operator==(r2))
    cout && "equal\n";