p3-euchre

Operator Overloading

In this project, you implement an output operator << and comparison operators <, <=, >, >=, ==, and != for the Card class. This appendix provides a quick tutorial on operator overloading with a simple Thing class as an example. We recommend you use these same patterns for your Card class.

Stream insertion operator

In C++, we use the stream insertion operator << (AKA output operator) to print built-in types. For example:

cout << "My favorite number is  " << 42 << endl;

We can also use this convenient mechanism for our own custom types. Consider a simple class called Thing that keeps track of an ID number:

class Thing {
  int id; //Things store their ID number
public:  
  Thing(int id_in) : id(id_in) {} // constructor
  int get_id() const { return id; }
};

We can add a function that lets us print a Thing object using cout, or any other stream. This is called an overloaded output operator. Notice that this is not a member function.

std::ostream& operator<< (std::ostream& os, const Thing& t) {
  os << "Thing # " << t.get_id(); //send output to "os"
  return os; //don't forget to return "os"
}

Now, we can print Thing objects just as conveniently as we can print strings and integers!

int main() {
  Thing t1(7);
  cout << t1 << endl; //use overloaded output operator
}

This produces the following output:

Thing # 7

Comparison operators

Let’s say that we also want to be able to check if two Thing objects are equal. For this, we’ll overload the == operator. Notice that this is not a member function.

bool operator==(const Thing& first, const Thing& second) {
  return first.get_id() == second.get_id();
}

Now, we can easily check two Thing objects for equality:

int main() {
  Thing thing_1(42);
  Thing thing_2(42);
  Thing thing_3(43);
  cout << thing_1 == thing_2 << endl; // true
  cout << thing_1 == thing_3 << endl; // false
}

Likewise, we could define a < operator to compare two Thing objects. In this case, we

bool operator<(const Thing& first, const Thing& second) {
  return first.get_id() < second.get_id();
}

What about the rest of the comparison operators? There are six total operators, but we can actually implement the remaining four by calling the two we’ve already done (== and <).

bool operator<=(const Thing& first,const Thing& second) {
  return first < second || first == second;
}
bool operator>(const Thing& first, const Thing& second) {
  return !(first <= second);
}
bool operator>=(const Thing& first, const Thing& second) {
  return !(first < second);
}
bool operator!=(const Thing& first, const Thing& second){
  return !(first == second);
}

Implementing the equality and comparison operators this way is highly recommended! Reusing code where possible means fewer lines to write and fewer places for bugs to hide!