Search

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)
```

If you need a refresher on std::sort, we talk about it in lesson 6.4 -- Sorting an array using selection sort.

Show Solution

• Nguyen

We have two objects to compare with each other in every example in this chapter
However, in quiz 2, we have only one object(vector array).  How could it compare with itself?
In line 56 requires an overloaded Car::operator<, Why not others?

I slightly modified the quiz 2 as shown below.
What is actually passed from the caller to Car::operator<()?
Could you please explain how my modified program works?

The output:

c1.m_make: Honda
c2.m_make: Toyota
c1.m_model: Accord
c2.m_model: Corolla

c1.m_make: Toyota
c2.m_make: Honda
c1.m_model: Corolla
c2.m_model: Accord

(Honda, Accord)
(Toyota, Corolla)

• nascardriver

`std::sort` uses `operator<` to compare the elements of the vector. A < operator is all that's needed to sort lists, as you've seen in the lesson about sorting. There appears to be some general confusion about how `std::sort` works. I'll see if I can improve on the lessons introducing it. Update: I added a note for advanced readers to section "Using std::sort to custom sort" of lesson 6.18.

• Nguyen

Hi,

x == y
x is the left operand.
== is the comparison.
y is the right operand.

"Because the comparison operators are all binary operators that do not modify their left operands"
I don't understand.  Could you please use my example to explain?

Thanks,

• nascardriver

== is a binary operator, because it has 2 operands.
It doesn't modify its left operand (x). x has the same value after the comparison as it had before.

• salah

I am getting an asserting error! what is the peoplem?

• nascardriver

What's the error message? Where is the error?

• salah

Hi, the problem is in this code line:

the asserting error is: "Debug asserting failed. Expression: Invalid comparator"

• nascardriver

• bob jones

in the quiz, when you overload the < operator with

how does the compiler know how to resolve the if and return lines? Why do you not need to first overload the == and < operators to take strings as parameters?

• nascardriver

`std::string`, like many other standard types, already has those operators. See https://en.cppreference.com/w/cpp/string/basic_string#Non-member_functions

• Constant_n

I prefer the short form for such comparisons:

And if we have more parameters, the function may be written like this:

• Ged

Why do we need these overloaded functions? Tested it without these ones and it worked fine.

• nascardriver

They're used in the first example of this lesson, but not needed in the quiz.

• Ryan

Is it recommend or preferable to use references in the parameters for these functions, like:

You are not changing the values for the objects, so what's the point in making c1 and c2 references?

• nascardriver

We use references for speed. We use `const` because we don't modify them. See lesson 7.3.

• David

The mini quiz was the first one iv'e had any real difficulty with and ultimately gave up and peeked at the answer. Unless I missed something the last time we touched std::sort it was essentially here is sort it sorts arrays when given a beginning and end. I don't remember going over how it actually worked even looking it up I could only really find examples on how to use it which all essentially said the same thing. Give it a starting point, and ending point and a third optional parameter that was how it would compare things.

Looking at the answer now it makes sense but I feel like if something as simple as:

//Note* std::sort by default compares two values and places whichever element it finds the smallest closer to the beginning of an array.

If that little bit of info was there it would have been a lot easier to work backwards how to get std::sort to do what you needed it to do. The second half of the mini quiz was fine though.

• Alex

I added a link to the lesson where we discuss std::sort and added a little context there. Thanks for the feedback.

• DecSco

Is there any disadvantage in defining the operator as

?

• It's exactly the same.

• 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:

• You didn't test with enough data

• masterOfNothing

That I did not. Thanks for pointing it out.

• 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:

• You can overload typecast operators (Lesson 9.10).
They can be used to write a custom conversion to bool.

• Anthony

Thank you nascardriver :) I was, as is fairly tyoical, barking up entirely the wrong tree

• 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

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.

• Hi Alex!

* Initialize your variables with uniform initialization. You used copy initialization.
* You're comparing the models even if @model_comp is not used.

• 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.

Ah k, thanks Alex!

• 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".

• Alex

Typos fixed. Thanks for pointing that out.

• 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.