I'm writing a card game (Dominion) as a pet project. I'm new to C++ but not programming.
A player has a deck, containing the hand and cards in play (tableau). Outside the player, there are piles of cards to buy from (supply piles). I want to display these objects (the hand, tableau and supply piles) on the screen. I had chosen to represent the hand and tableau using std::vector<Card> and the supply piles as std::vector<SupplyPile>. Card and SupplyPile implement an interface for displaying contents to the screen
class IInfo {
public:
virtual std::string Info() const = 0;
virtual std::string ToString() const = 0;
};
I have a class I'm calling View that will take on displaying things to the screen.
class View {
public:
View(const std::vector<IInfo*>& items, int window_starty, int window_startx);
virtual ~View() { }
const IInfo& CurrentItem() const;
const int CurrentIndex() const;
bool IsEmpty() const;
void ItemDown();
void ItemUp();
void SetActive();
void SetInactive();
virtual void Update();
protected:
virtual WINDOW* InitializeWindow(int lines,
int cols,
int starty,
int startx);
virtual ITEM** MakeMenuItems();
private:
// Some constants
const std::vector<IInfo*>& items_;
MENU *menu_;
WINDOW *window_;
};
I now know that C++ doesn't support covariance in templates, so I can't create instances of View with the supply pile, hand, and tableau. How can I redesign the system to maximize DRY? The View class operates on its container member in a very simple way, ripe for abstraction.
Examples of things I want to do
std::vector<Card> hand = player.hand();
std::vector<Card> tableau = player.tableau();
std::vector<SupplyPile> supply_piles = game.supply_piles();
View hand_view = new View(hand, starty, startx);
View tableau_view = new View(tableau, starty, startx);
View supply_piles_view = new View(supply_piles, starty, startx);
One answer suggested making View into a template, and it almost worked until I remembered that I want to track which View is active at a given time:
View active_ = hand_view;
// Later
active_ = supply_piles_view;
I can't do this with View<Card> and View<SupplyPile>.
Other code
class Card : public IInfo {
public:
Card(std::string name,
int cost,
int initial_supply,
std::string text,
std::string type);
~Card();
void Play();
std::string Info() const;
std::string ToString() const;
int cost() const;
int initial_supply() const;
std::string name() const;
std::string text() const;
private:
int cost_;
int initial_supply_;
std::string name_;
std::string text_;
std::string type_;
std::string set_;
};
class SupplyPile : public IInfo {
public:
SupplyPile(const Card& card, int initial_count);
SupplyPile(const SupplyPile& other);
virtual ~SupplyPile();
virtual bool operator==(const SupplyPile& other) const;
bool BuyOrGain();
std::string Info() const;
std::string ToString() const;
const Card& card() const;
int count() const;
std::string name() const;
private:
const Card& card_;
int count_;
};
std::vector<IInfo*> x;then you can dopush_back(new Card(...),push_back(new SupplyPile(...)). Templates aren't covariant, no, so if you havetemplate <typename T> class FoothenFoo<A>andFoo<B>are totally separate types for anyAandB(even if B derives from A), but I don't see where that's an issue in any of your code. – Yuushi Feb 9 at 4:56