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 Foo
thenFoo<A>
andFoo<B>
are totally separate types for anyA
andB
(even if B derives from A), but I don't see where that's an issue in any of your code. \$\endgroup\$