12.4. The equals function¶
In order for two cards to be equal, they have to have the same rank and
the same suit. Unfortunately, the == operator does not work for
user-defined types like playing_card, so we have to write a function that
compares two cards. We’ll call it equals. It is also possible to
write a new definition for the == operator, but we will not cover
that in this book.
It is clear that the return value from equals should be a boolean
that indicates whether the cards are the same. It is also clear that
there have to be two playing_cards as parameters. But we have one more
choice: should equals be a member function or a free-standing
function?
As a member function, it looks like this:
bool playing_card::equals (const playing_card& c2) const {
return (rank == c2.rank && suit == c2.suit);
}
To use this function, we have to invoke it on one of the cards and pass the other as an argument:
playing_card card1 (1, 11);
playing_card card2 (1, 11);
if (card1.equals(card2)) {
std::cout << "Yup, that's the same card." << std::endl;
}
This method of invocation always seems strange to me when the function
is something like equals, in which the two arguments are symmetric.
What I mean by symmetric is that it does not matter whether I ask “Is A
equal to B?” or “Is B equal to A?” in this case, I think it looks better
to rewrite equals as a nonmember function:
bool equals (const playing_card& c1, const playing_card& c2) {
return (c1.rank == c2.rank && c1.suit == c2.suit);
}
When we call this version of the function, the arguments appear side-by-side in a way that makes more logical sense, to me at least.
if (equals (card1, card2)) {
std::cout << "Yup, that's the same card." << std::endl;
}
Of course, this is a matter of taste. My point here is that you should be comfortable writing both member and nonmember functions, so that you can choose the interface that works best depending on the circumstance.
Run the active code below to see how the equals() function works.
1#include <iostream>
2#include <string>
3#include <vector>
4
5struct playing_card {
6 int suit, rank;
7
8 playing_card ();
9 playing_card (int s, int r);
10 void print () const;
11 bool equals (const playing_card& c2) const;
12};
13
14int main() {
15 playing_card card1 (1,11);
16 playing_card card2 (1,11);
17 playing_card card3 (3,11);
18 card1.equals(card2);
19 card1.equals(card3);
20}
How can we compare two Card objects?
Should we write the equals() function as a free-standing function, or as a member function of Card?
in a card game called Euchre, the highest ranked suit is called the trump suit. The trump suit contains all of the cards of that suit, and the Jack of the other suit of the same color. For example, if Hearts was trump, the trump suit would contain all Hearts, and the Jack of Diamonds. Implement the is_trump() function that returns true of a playing_card is part of the trump suit. Assume we have a helper function same_color() that returns the other suit of the same color.
-
bool playing_card::is_trump (std::string trump_suit) { -
else if (rank == "Jack" && suit == same_color()) { return true; } -
else if (rank == "Jack") { return true; } -
else { return false; } -
if (suit != trump_suit) { return false; } -
if (suit == trump_suit) { return true; } -
} -
};