I'm attempting to improve my coding style by concentrating on simple and focused OOP client-server interfaces and error handling - atm in the context of designing a Blackjack game. I'm starting with the Card class that represents an individual card. I'm looking for any improvements on or flaws with my approach.
#include <sstream>
#include <stdexcept>
#include <string>
class Card
{
public:
enum Ranks { Ace = 1, Ten = 10, Jack, Queen, King };
enum Suits { Spades, Hearts, Diamonds, Clubs };
Card( int rank, int suit ) throw(std::range_error)
{
if( rank < 1 || rank > 13 ) {
std::stringstream errMsg;
errMsg << "Card(): rank '" << rank << "' out of range";
throw std::range_error( errMsg.str() );
} else if( suit < 0 || suit > 3 ) {
std::stringstream errMsg;
errMsg << "Card(): suit '" << suit << "' out of range";
throw std::range_error( errMsg.str() );
}
m_rank = rank;
m_suit = suit;
}
int rank() const { return m_rank; }
int suit() const { return m_suit; }
std::string str( bool useStrings = false ) const
{
std::stringstream ret;
if( useStrings )
ret << sRanks[m_rank] << " of " << sSuits[m_suit];
else
ret << cRanks[m_rank] << cSuits[m_suit];
return ret.str();
}
private:
static const char cRanks[14];
static const char cSuits[4]
static const std::string sRanks[14];
static const std::string sSuits[4];
int m_rank;
int m_suit;
};
const std::string Card::sSuits[4] = {"Spades", "Hearts", "Diamonds", "Clubs"};
const std::string Card::sRanks[14] = { "\0", "Ace", "Two", "Three", "Four", "Five",
"Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King" };
const char Card::cSuits[4] = { 's', 'h', 'd', 'c' };
const char Card::cRanks[14] = { '\0', 'A', '2', '3', '4', '5', '6', '7',
'8', '9', 'T', 'J', 'Q', 'K' };
The client can create a card either using the Card enum constants or integers, like
Card card(Card::Ace, Card::Diamonds);
Card card2(0, 3); // throws an exception
I'm dubious on how useful the public enum constants are for client code. Also, I'm very new to exception programming and I'm not sure if this is a good approach or whether the constructor should throw an exception. Any improvements or suggestions?