Search

9.6 — Overloading the comparison operators

Overloading the comparison operators is comparatively simple (see what I did there?), as they follow the same patterns as we’ve seen in overloading other operators.

Because the comparison operators are all binary operators that do not modify their left operands, we will make our overloaded comparison operators friend functions.

Here’s an example Car class with an overloaded operator== and operator!=.

The code here should be straightforward. Because the result of operator!= is the opposite of operator==, we define operator!= in terms of operator==, which helps keep things simpler, more error free, and reduces the amount of code we have to write.

What about operator< and operator>? What would it mean for a Car to be greater or less than another Car? We typically don’t think about cars this way. Since the results of operator< and operator> would not be immediately intuitive, it may be better to leave these operators undefined.

Recommendation: Don’t define overloaded operators that don’t make sense for your class.

However, there is one common exception to the above recommendation. What if we wanted to sort a list of Cars? In such a case, we might want to overload the comparison operators to return the member (or members) you’re most likely to want to sort on. For example, an overloaded operator< for Cars might sort based on make and model alphabetically.

Some of the container classes in the standard library (classes that hold sets of other classes) require an overloaded operator< so they can keep the elements sorted.

Here’s a different example with an overloaded operator>, operator<, operator>=, and operator<=:

This is also pretty straightforward.

Note that there is some redundancy here as well. operator> and operator<= are logical opposites, so one could be defined in terms of the other. operator< and operator>= are also logical opposites, and one could be defined in terms of the other. In this case, I chose not to do so because the function definitions are so simple, and the comparison operator in the function name line up nicely with the comparison operator in the return statement.

Quiz time

1) For the Cents example above, rewrite operators < and <= in terms of other overloaded operators.

Show Solution

2) Add an overloaded operator<< and operator< to the Car class at the top of the lesson so that the following program compiles:

This program should produce the following output:

(Honda, Accord)
(Honda, Civic)
(Toyota, Camry)
(Toyota, Corolla)

Show Solution

9.7 -- Overloading the increment and decrement operators
Index
9.5 -- Overloading unary operators +, -, and !

102 comments to 9.6 — Overloading the comparison operators

  • DecSco

    Is there any disadvantage in defining the operator as

    ?
    Readability aside, maybe.

  • masterOfNothing

    Hi, in the quiz where we had to overwrite operator< (Car, Car) for Car class, I found out this worked with std::sort function as well:

  • The two-way comparison operator expressions have the form:

    lhs < rhs    (1)    
    lhs > rhs    (2)    
    lhs <= rhs    (3)    
    lhs >= rhs    (4)    
    lhs == rhs    (5)    
    lhs != rhs    (6)

    1) Returns true if lhs is less than rhs, false otherwise.
    2) Returns true if lhs is greater than rhs, false otherwise.
    3) Returns true if lhs is less than or equal to rhs, false otherwise.
    4) Returns true if lhs is greater than or equal to rhs, false otherwise.
    5) Returns true if lhs is equal to rhs, false otherwise.
    6) Returns true if lhs is not equal to rhs, false otherwise.
    In all cases, for the built-in operators, lhs and rhs must have either
    arithmetic or enumeration type
    pointer type
    Then there are Arithmetic comparison operators, pointer comparison operators, three-way comparison...

    Just a little note for y'all :)

  • Anthony

    Hi,

    What is the correct form of the == operator where instead of:

    we have:

    Imagine that MyObject has a pointer member variable m_ptr, and we want to test whether this pointer has been initialised. I'm thinking along the lines of:

  • Tommy

    Hello, forgive the constant confirming

    Because we are only overloading the operators to manage car classes, does that mean that std::sort can compare strings and sort accordingly? Does it do this by taking the first character's ASCII code and converting it into an int?

    • @std::sort can sort everything that has an @operator<.
      @std::string::operator< compares strings char by char, until the strings differ. char is an integral type, there's no need for a conversion.

  • Jack

    Q2. my version of overloaded operator< function.

    • Hi Jack!

      Your code will work in most cases. Not all

      c1: hond acivic
      c2: honda civic

      Correct answer: c1 < c2
      Your answer: !(c1 < c2)

      On top of that, your code constructs 2 temporary strings, which is slow.

  • Alex

    In case anyone is interested. I used the compare function of string and it worked.

  • Marcos O.

    Hi!

    Regarding Quiz(2), in the solution why are the == and != operators overloaded? Aren't the values they compare already resolved to pseudo-fundamental strings when operator < is used? Also wouldn't it be preferable for operator< to be a member function of Car as the left most operand is of type Car?

    My solution to Q(2):

    • > why are the == and != operators overloaded?
      They're not used in this quiz, I don't know why Alex added them. It's worth mentioning that C++ doesn't offer default operator== and operator!=. If you want to compare objects of your class, you need to define those operators manually.

      > Aren't the values they compare already resolved to pseudo-fundamental strings when operator < is used?
      I'm not sure what you mean. @Car::operator< doesn't make use of @Car::operator== or @Car::operator!=. It used @std::string's operators.

      > Also wouldn't it be preferable for operator< to be a member function of Car as the left most operand is of type Car?
      Lesson 9.4 says not to do so, because with a non-member function it'd be easier to swap the order of the parameters, which doesn't matter in this case.

      > My solution
      I'm skipping @main, because you copied it.
      * Line 4, 5, 9: Initialize your variables with uniform initialization. @m_make and @m_model will be initialized anyway, but if you initialize everything, you won't forget to when you need it.

      • Alex

        The overloaded operator== and operator!= were in the original Car program that the quiz question is extending. Even though they're not used, there's no harm in having them there since it's just a copy/paste from above.

      • Marcos O.

        >...C++ doesn't offer default operator== and operator!=. If you want to compare objects of your class, you need to define those operators manually.
        If c++ doesnt offer default == or != then how are they used for

        where the operator isn't defined or a simpler case

        Int in the above example is just to indicate type of x and y, not be correct code.
        And what do you define as "default", is the std library and string library "default"? Is it because we arent comparing the objects of defined class  (which would require overloading operator) instead the string objects within?

        >It used @std::string's operators
        Thank you for confirming, thats exactly what I meant, I just wanted to make sure.

        >Lesson 9.4 says not to do so, because with a non-member function it'd be easier to swap the order of the parameters, which doesn't matter in this case.
        Isnt this case specifically to compare an object of the same type with an object of our defined type as reference? Isn't a case where your defined object is the reference one of the specific times to use a member function?

        >* Line 4, 5, 9: Initialize your variables with uniform initialization
        Line 4, 5: I thought we werent supposed to initialize a variable both at definition and construction. Is that only if initialized with a value?
        Line 9: VS2013 doesn't seem to like uniform initialization and often throws me errors when I try. Do you have any tips or suggestions around these errors?

        Thank you for your help. I would have further appreciated if you left your assumption about me copying @main out.

        • > And what do you define as "default"
          Types you write yourself. int, double and other native types have operators. @std::string is a class, it has those operators, whoever wrote the @std::string class that's being used on your system wrote those operators.

          > Isnt this case specifically to compare an object of the same type [...]
          Sorry, I'm having a hard time trying to understand what you're asking.

          >  I thought we werent supposed to initialize a variable both at definition and construction
          I don't know what you're referring to. Mind sharing the lesson?
          Initialize all variables. If possible, to a specific (0) value. @std::string has a default constructor, so just use empty curly brackets.

          > VS2013 doesn't seem to like uniform initialization and often throws me errors when I try
          If this happens sometimes, but not always, you're doing something wrong (Or there's a compiler bug, which is unlikely). If it never allows uniform initialization, upgrade your compiler.

          > I would have further appreciated if you left your assumption about me copying @main
          Initialize @v instead of manually pushing all elements. Also, uniform initialization.

  • Khang

    I think the right spelling is "nickel" not "nickle".

  • i don't understand in second quiz some answers make the program crash such as doing this:
    return (c1.m_make < c2.m_make) || (c1.m_model < c2.m_model)
    if one or the other is alphabetically out of order sort it , even if it won't do exactly what is required.
    does this have to do something with the iterators ?

    • Hi Michael!

      Your @operator< is invalid, because it allows car A to be smaller than car B, but at the same time B is smaller than A.

      Depending on the implementation of @std::sort, this could cause infinite loops, exceptions or crashes.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]