Let’s take it a step further. What if we literally wanted to type a < b as if our fraction were a primitive data type? We can actually do that! The boilerplate is a little bit of a hassle to remember, but you will want to memorize it because many things in the standard libraries depend on your objects being able to compare themselves. The code goes like this:

#include <stdio.h>

struct fraction {
int numerator;
int denominator;

bool operator<(const fraction& second) const {
if (this->numerator * second.denominator < second.numerator * this->denominator) {
return 1;
}
return 0;
}

bool operator==(const fraction& second) const {
if (*this < second || second < *this) {
return 0;
}
return 1;
}

bool operator>(const fraction& second) const {
if (second < *this) {
return 1;
}
return 0;
}
};

fraction fraction_new(int numerator, int denominator) {
fraction f;
f.numerator = numerator;
f.denominator = denominator;
return f;
}

main() {
fraction a = fraction_new(1, 2);
fraction b = fraction_new(3, 4);

// Compare two fractions
printf("a < b is %d\n", a < b);
printf("a == b is %d\n", a == b);
printf("a > b is %d\n", a > b);
}


Success! We’ve managed to implement the basic comparison operators. Let’s try using our code with the standard library.

#include <algorithm>

// Copy the fraction definitions and fraction_new here

main() {
fraction a = fraction_new(1, 2);
fraction b = fraction_new(3, 4);

// Get the larger of two fractions
fraction larger = std::max(a, b);
printf("The larger one is %d / %d\n", larger.numerator, larger.denominator);

// Sort three fractions in an array
fraction arr[3] = { fraction_new(5, 6), fraction_new(3, 4), fraction_new(1, 2) };
std::sort(arr, arr+3);
for (int i=0; i<3; i++) {
printf("%d / %d\n", arr[i].numerator, arr[i].denominator);
}
}


Yay it works! Interestingly, std::sort and many others in the standard library don’t need us to define anything except the operator<. Those libraries figure out == and > in the same way that we defined everything from just the less than operator. Again, make sure to memorize at least how to define the < operator so you can use the standard library with custom objects. We’ll slowly go through the custom library as we progress in our discussions of algorithms.

Going a step further, you can define almost all of the operations in C++ yourself. For example, cin defines the >> operator to store input values in variables. vector redefines the [] operator to behave like an array. Those are possible, so there’s nothing stopping you from doing the same. There’s a full list of operators you can overload in wikipedia along with "prototype examples" on what the method declarations should look like.