C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
37: Operator Overloading: Comparison Operators
I was working on a small plugin manager the other day and realized I needed a way to check if a user's installed version of a library was compatible with a required version. Naturally, I built a Version struct to hold the major, minor, and patch numbers. It seemed simple enough.
struct Version {
int major;
int minor;
int patch;
};
Version v1{1, 2, 0};
Version v2{1, 2, 1};
if (v1 == v2) {
// Do something
}
The compiler's lack of intuition
When I tried to compile that, the compiler immediately complained. It had no idea what == meant when applied to two Version objects. To us, it's obvious: "just check if all the numbers match." To C++, a struct is just a blob of memory. It doesn't assume you want a member-wise comparison.
So, I need to tell C++ how to handle this. I'll overload the == operator. I'll make it a const member function because comparing two versions shouldn't change the versions themselves.
struct Version {
int major, minor, patch;
bool operator==(const Version& other) const {
return major == other.major &&
minor == other.minor &&
patch == other.patch;
}
};
Now v1 == v2 works. But here's where things get tedious. In a versioning system, I don't just need to know if they are equal; I need to know if one is older than the other so I can trigger an update. I tried if (v1 < v2), and—surprise—another compiler error.
The logic of "Less Than"
Implementing operator< is trickier than equality. I can't just check if major < other.major && minor < other.minor... because if the major version is higher, the minor version doesn't even matter. 1.0.0 is always newer than 0.9.9, regardless of that 9.
I'll try to write this out logically: check the major version first. If they're different, that's my answer. If they're the same, move to the minor. If those are the same, move to the patch. It looks like this:
bool operator<(const Version& other) const {
if (major != other.major) return major < other.major;
if (minor != other.minor) return minor < other.minor;
return patch < other.patch;
}
This works, but I'm already feeling the friction. If I want to support >, <=, and >=, am I really going to write five different functions that all do essentially the same comparison logic? That's a recipe for a typo and a nightmare to maintain.
The "Spaceship" Shortcut
If you're using C++20 or newer, there is a much more elegant way to handle this. There's a new operator called the three-way comparison operator, or the "spaceship operator" (<=>) because of how it looks. Instead of returning a boolean, it returns a value that tells you if the left side is less than, equal to, or greater than the right side.
The real magic happens when you use = default. Let's see what happens if I replace all my manual comparison operators with this:
#include <compare>
struct Version {
int major, minor, patch;
auto operator<=>(const Version& other) const = default;
};
By defaulting the spaceship operator, C++ automatically generates ==, !=, <, >, <=, and >= for me. It does exactly what I did manually: it compares the members in the order they are declared in the struct. Since I declared major, then minor, then patch, the lexicographical comparison happens automatically.
I've spent years writing those tedious if (a != b) return a < b; blocks. Using <=> is a massive quality-of-life improvement. Just remember that if you need a custom comparison logic—like if a certain version flag overrides everything else—you'll have to write the <=> logic yourself instead of defaulting it.
📋 Practical Task
Implementing a Coordinate Distance Comparison
You are building a 2D game engine. You have a Point struct with x and y coordinates. You want to be able to compare two Point objects based on their distance from the origin (0,0). A point is considered "less than" another point if it is closer to the origin.
Your Task:
- Create a
Pointstruct withdouble xanddouble y. - Overload the
==operator to check if two points are at the exact same coordinates. - Overload the
<operator to compare their distance from the origin using the formula: $\sqrt{x^2 + y^2}$. (Note: For optimization, you can compare $x^2 + y^2$ instead of taking the square root). - Write a
mainfunction that creates three points:p1{1.0, 1.0},p2{0.0, 2.0}, andp3{5.0, 5.0}. - Print whether
p1 < p2and whetherp1 == p2.
There are no comments for now.