2

I have classes Deck, abstract class Card and Spell and Minion which are both derived from Class. I have vector<unique_ptr<Card> > of all existing Cards and now I want to place them into Decks. I want to use void Deck::addCard(<unique_ptr<Card>) overloads for Minion and Spell.

I've tried changing the arguments and parameters to "dumb" * pointer, or just Card (which can't work, I know), references, non-references etc...

Calling addCard

Deck tmp;
for( const auto & it : mAllCards )
{
  cout << typeid( *it ).name() << endl;
  tmp.addCard( it );
}

addCard functions

void Deck::addCard( const unique_ptr<Card> & card )
{
    cout << "basic" << endl;
}

void Deck::addCard( const unique_ptr<Minion> & minion )
{
    cout << "minion" << endl;
}

void Deck::addCard( const unique_ptr<Spell> & spell  )
{
    cout << "spell" << endl;
}

The problem is that the Card version is called everytime, not the variants for derived types. Althrough typeid says Minion or Spell, not Card.

second32
  • 83
  • 1
  • 9
  • Do you really use `Deck tmp();` in the code? It is a function prototype for a function named `tmp`, which takes no parameters and returns a `Deck`. – mch May 07 '19 at 07:49
  • Please post a [mcve] you have omitted most of the relevant code. – Richard Critten May 07 '19 at 07:49
  • What do you want to store in `Deck`? References to cards in a vector? Their copies? In the first case, just store references to `Card`. In the second case, you likely want some form of a _clone pattern_, see, e.g., https://stackoverflow.com/q/39905802/580083. – Daniel Langr May 07 '19 at 07:51
  • No, I don't, sorry, error in simplifying the code. – second32 May 07 '19 at 07:51
  • Yes, I want to make a copy, I'll look at it, thanks – second32 May 07 '19 at 07:54

1 Answers1

3

It doesn't work because overloads in C++ are resolved at compile time.

You should considere using a virtual print function from Card.

Something like this.

class Card {
public:
    virtual void print() { std::cout << "basic" << std::endl; }
}

class Minion : public Card {
public:
    void print() override { std::cout << "minion" << std::endl; }
}

class Spell : public Card {
public:
    void print() override { std::cout << "spell" << std::endl; }
}

Then to use this print function you'll do this way.

void Deck::addCard(const unique_ptr<Card>& card)
{
    card.print();
}

Otherwise there's always double dispatch pattern or maybe visitor pattern.

Found all this in this old post.

  • This doesn't really answer the question. `addCard` method should be a part of `Deck` class, not `Card` class, so making functions virtual is not helpful. – Yksisarvinen May 07 '19 at 08:42
  • Yes, it works now, thank you. I wanted to have just Deck::AddCard not Card::AddToDeck, but it's not posibble from what I read. I will probably remove the AddCard and leave just AddToDeck, since the function makes no sense now, it only calls the other one. – second32 May 07 '19 at 08:44
  • Actually, I'm just making the print function virtual. The `addCard` is still a part of `Deck`. – Ulysse Regnier May 07 '19 at 09:22