Reputation: 627
Say you have a std::vector class that holds type Item, and you store inherited types of items: Weapon, Potion, Armor, etc. How do you retrieve the item as the inherited class and not the base?
Upvotes: 2
Views: 100
Reputation: 38939
Your design has a bad smell in it. Storing item*
has the unfortunate cost of having to manage them outside the vector
. The only good motivation for a vector<item*>
would be to use the item
s polymorphically. By trying to detect the type you're demonstrating that you are not using them polymorphically.
A better solution would be to store these items in separate vectors, rather than a communal vector<item*> items
, so vector<weapon> weapons
, vector<potion> potions
, vector<armor> armors
.
So please don't use this code, but given vector<item*> items
you can do this:
for(auto i : items) {
if(dynamic_cast<weapon*>(i) != nullptr) {
auto iWeapon = static_cast<weapon*>(i);
// work with weapon here
} else if(dynamic_cast<potion*>(i) != nullptr) {
auto iPotion = static_cast<potion*>(i);
// work with potion here
} else {
assert(dynamic_cast<armor*>(i) != nullptr);
auto iArmor = static_cast<armor*>(i);
// work with armor here
}
}
Upvotes: 2
Reputation: 93334
How do you retrieve the item as the inherited class and not the base?
This suggests that you need closed-set polymorphism, which is provided by std::variant
or boost::variant
.
using Entity = std::variant<Weapon, Potion, Armor>;
// An `Entity` is either a `Weapon`, a `Potion`, or an `Armor`.
std::vector<Entity> entities;
struct EntityVisitor
{
void operator()(Weapon&);
void operator()(Potion&);
void operator()(Armor&);
};
for(auto& e : entities)
{
std::visit(EntityVisitor{}, e);
// Call the correct overload depending on what `e` is.
}
Upvotes: 6