2

I have class Item, one of no interest itself. However, I need some Items to be gear like clothes or weapons which need to additionally store an enum class Limb object which represents the body part where they can be equipped. Moreover, ordinary Items must be placed together with "gear" Items in a single STL container and possibly be taken out later, maybe as a "gear" Item. I see two options here: inheritance

class Item { /* ... */ };
class Gear : public Item {
  Limb limb;
// ...
};
std::vector<std::unique_ptr<Item>> items;
std::unique_ptr<Gear> gear = // dynamic cast items[...] and check for success

or std::optional

class Item {
  std::optional<Limb> limb; // if equippable, limb.has_value() == true
// ...
};
std::vector<Item> items;
Item gear = // get items[...] and check limb.has_value()

I like the first one for extensibility and compile-time type checking when a function expects Gear (not just an Item) instead of a runtime assert(item.is_gear()) inside it.

The second one seems better in terms of speed (I like to care about it even when there are no performance issues expected) and design naturalness: I don't need to know about any other classes and special use cases when engineering Item (for example, making its destructor virtual like in the first variant would destroy this) which seems like clean and innocent design.

Which decision would be better and why? Or is there an even better solution?

passing_through
  • 703
  • 2
  • 12
  • Does it make sense for an Item (or Gear) to "have-a" limb? Or should the Limb(s) be elsewhere (on the player, monster, creature, entity, ...) and the Items etc. have a pointer/reference/identifier as to which limb they are on? Incidentally, `Item gear = ` will result in [object slicing](https://stackoverflow.com/questions/274626/what-is-object-slicing). – 1201ProgramAlarm Feb 09 '20 at 21:16
  • @1201ProgramAlarm I understand `Item`s' `limb` as the information where they should be worn. After all, it's just an `enum` object, not the limb itself. Besides, there's only one `Limb` where an `Item` is supposed to be on (maybe none). – passing_through Feb 09 '20 at 21:26
  • It is unclear from the question what, exactly, `Limb` is. I assumed it was a class. [Edit] the question to include that detail. That then opens up the possibility of a `Limb` value for `NO_LIMB`, which you could use instead of `std::optional` to indicate something is not equippable/equipped. – 1201ProgramAlarm Feb 09 '20 at 21:29
  • @1201ProgramAlarm it is stated `Limb` is an `enum class` above the code. I don't like `Limb::none` as it's dependent design: it leads to shaping `Limb` like I need in one (!) of use cases, so `Limb`'s "logic" loses independency. Nevertheless, even if I make a "null" value, I would like to deeply compare it with the first approach in the question. – passing_through Feb 09 '20 at 21:39
  • A minor point, but this discussion shows how naming variables well helps Instead of "Limb limb", a name like "Limb placement" might have helped. – Ian4264 Feb 09 '20 at 21:56
  • @lan4264 `placement` is still imperfect: for example, someone's inventory may be an `Item`'s placement :D I actually prefix enums in my usual code so it should be clear anyway; in examples here I'm sticking to a more widely-used convention. – passing_through Feb 09 '20 at 22:01

0 Answers0