2

I'm trying to learn C++ by converting a few Java classes I made a while ago. They represent a playing card and a deck of cards. I'm using an enum for the values and suits as such:

enum Suits{SPADES, CLUBS, HEARTS, DIAMONDS};

enum Values{TWO, THREE, FOUR, FIVE, 
            SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE};

In both my Java and C++ Card class I have methods: getValue() and getSuit() which obviously return the value and suit respectively.

My Java DeckofCards class is pretty simple:

public class DeckofCards {

private Card card; 
private String value;
private String suit;
private List<Card> deck = new ArrayList<Card>();

//DeckofCards constructor
public DeckofCards(){
    for (Suits s : Suits.values()) {
        for(Values v : Values.values()){
            card = new Card(v,s);
            deck.add(card);
        }  
    }
}

//shuffles the deck
public void shuffleDeck(){
    Collections.shuffle(deck);
}

//prints the deck of cards
public void printDeck(){

    for(int i = 0; i<deck.size(); i++){
        card = deck.get(i);
        value = card.getValue().toString();
        suit = card.getSuits().toString();
        System.out.println(value + " of " + suit);
    }

}

//draws a card from the deck
public Card drawCard(){
    try{
        card = deck.get(0);
        deck.remove(0);
        //return card;
    }
    catch(IndexOutOfBoundsException e){
        System.err.println("Deck is empty");
        System.exit(0);
    }
    return card;
}

} 

My problem is implementing the printDeck() method in C++, specifically getting the string representation of the enum values. I know I can't simply do getValue().toString() So my idea after doing some research on the matter was to make two std::string[] that look the same as the two enums and then use the getValue() and getSuit() to generate an int (since that seems to be the behavior) and pass that into the array to get the string representation.

However I'm now thinking that it might be better to add two more methods in my Card class:

std::string getValue(int i) and likewise for suit

and use a case statement to return a string value based on the int so that other classes can easily get the string representation. This seems redundant though. Can anyone provide any suggestions on how to do this?

2
  • Why not overload ostream& operator<<(ostream&,Suit) if you just want to print it? You also get a string back out using ostringstream. Commented Mar 20, 2014 at 18:16
  • See stackoverflow.com/q/201593/10077. We're using X-macros where I work. Commented Mar 20, 2014 at 18:21

2 Answers 2

2

You can use new C++11 enum classes (i.e. scoped enums), and define a function that takes such an enum class as input parameter, and returns the corresponding string representation for the input enum value.

e.g.:

#include <assert.h>     // For assert()
#include <iostream>     // For console output
#include <string>       // For std::string

enum class Suits {
    SPADES, CLUBS, HEARTS, DIAMONDS
};

std::string toString(Suits s) {
    switch (s) {
    case Suits::SPADES:     return "Spades";
    case Suits::CLUBS:      return "Clubs";
    case Suits::HEARTS:     return "Hearts";
    case Suits::DIAMONDS:   return "Diamonds";
    default:
        assert(false);
        return "";
    }
}

int main() {
    std::cout << toString(Suits::CLUBS) << std::endl;
}

You can do a similar thing for the Values enum.

Sign up to request clarification or add additional context in comments.

6 Comments

Do I still define this in my card.hpp header? Or will this be separate?
@rsay3: The enum class definition must go in the card.hpp header (since clients will use this enum class). Then you're free to either 1. just insert the toString() function/method prototype in the header, and its definition in the .cpp file, or 2. put also the definition in the header, using the inline keyword (to avoid violations of the "one definition rule"). You may also want to read "C++ classes without .cpp file?".
Ok, and would toString() be a non-member function?
@rsay3: I don't how you organized your code. If you have the Suits enum class as a nested class of DeckOfCards, then you may want to make toString() a static member function of DeckOfCards as well. (I suggest using static in this case, since this toString() overload is not specific to any instance of DeckOfCards, i.e. it does not depend on the internal state of DeckOfCards: you just pass an enum value to it, and it returns the corrsponding string.)
My Suits and Values are not in my DeckofCards class, they are only defined in the header of my Cards class
|
1

In C++ there's no metadata around enums, so if you want a string version you need to write a converter yourself.

I'd probably go with something like this, this doesn't compile but you get the rough picture.

enum Suit { ... }
enum Values { ... }

Class card {
public:
   static std::string getText(Suite s) { switch(s) case CLUBS: return "clubs"; ... }
   static std::string getText(Colour c) { switch(c) case ONE: return "one"; ... }

   card(Suite s, Colour c) : mSuite(s), mColour(c) {}
   std::string getText() const {
       stringstream ss;
       ss << getText(mColour) << " of " << getText(mSuits);
       return ss.str();
   }
};
ostream& operator<<(ostream& stream, const card& c) {
    stream << c.getText();
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.