2

I'm making a text based adventure game (original, I know.) and I hit a problem. I want to let the player pick up an item, and then automatically put it where it belongs based on the subclass of Item that it belongs to. I have it set up so that when the player types "get " followed by the name of an object in the current room, the following function is called:

void Game::PickUp(Item * item)
{
    m_map.at(m_player.GetLoc())->RemoveItem(item); //Remove item from the room
    m_player.AddItem(item); //Add item to the player
}

Within the Player class I've overloaded AddItem(…) as follows:

void AddItem(Armor* armor)
{
    delete m_armor;
    m_armor = armor;
}
void AddItem(Weapon* weapon)
{
    delete m_weapon;
    m_weapon = weapon;
}
void AddItem(Shield* shield)
{
    delete m_shield;
    m_shield = shield;
}
void AddItem(Item* item)
{ 
    m_pack.push_back(item); 
}

When I run the code, it only calls void AddItem(Item* item), which makes sense because that's what's passed into the previous function, but since the object being passed is held in a vector<Item*> I can't pass it as anything else. Is there a way to detect the subclass of the object being passed and call the correct overload?

Nick Porter
  • 163
  • 8

1 Answers1

0

What you're looking for is called multiple dispatch. Since the determination of which override is called is made at compile time based on the static type of the parameter, you'll need to call a function that can make use of the run time type of the object to then call back into the original Player object.

In your Item base class, you'll declare the base case for this function:

virtual void AddToPlayer(Player &player);

It is defined as

void Item::AddToPlayer(Player &player) {
    player.AddItem(*this);
}

This doesn't do anything different than you already have. However, you can add an override of AddToPlayer to each class, whose definition is identical to the base class's given above. Since the type of *this will be different in each definition, a different overload of Player::AddItem will be called.

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
  • I'm trying to implement this, but since I have `#include "Item.h"` in my Unit.h header, my compiler won't let me `#include "Unit.h"` in Item.h (`Player` is a subclass of `Unit`). Is there a workaround for this? – Nick Porter Jun 20 '18 at 17:33
  • 1
    @JasonNickPorter You can forward declare a class by simply saying `class Player;` or `class Unit;` without including the header that defines the class. Then include the header in the .cpp file when you need the details of the class. – 1201ProgramAlarm Jun 20 '18 at 19:54