For example, sword and axe are two different classes, both inheriting
from weapon. Weapon and potion are also different classes both
inheriting from item.
I wouldn't do things this way; a sword and an axe differ mostly in their data, not their fundamental behaviors as weapons. Likewise with items. I would avoid this overuse of inheritance, starting by restricting yourself to just
Item (you could even fold these into a single class, but that's a different discussion). If nothing else this will alleviate the constructor explosion you're seeing in
So it has to be a
container of item (smart) pointers. Since I don't want to liter my
code with calls to new and delete, I'll wrap it in an ItemWrapper
class which news/deletes on ctor/dtor.
Consider the Boost smart pointers instead of rolling your own. They're fairly isolated from the rest of Boost (so you don't have a ton of dependencies to pull in if, for some reason, you don't want to take advantage of the rest of Boost's neat stuff), and many of them have been adopted to be part of the new standard library in C++11, so you shouldn't have issues upgrading.
This is my first attempt at this, so I'd like to know: am I going the
right way? or if there's a better way of doing it (perhaps one that
avoids so many constructors)?
As above, I would strive to avoid inheritance for this, and consider using established third-party solutions instead of rolling your own. Those steps alone should remove much of the maintenance complexity you're discovering (or will shortly discover).
That said, another approach is to look at it this way:
ItemWrapper is a band-aid for an implementation detail problem. It itself doesn't represent a real "object" in any typical sense. So think about what might be a better analogy that also solves your problem of having a place to put the automatic
Most inventories allow (some) items to stack, do they not?
The "stackability" of an item is a property of that item, but the item itself should not be responsible for maintaining the stack. If you have a class representing an
ItemStack with methods to query the size of the stack, split the stack, et cetera then you can put your management of the lifetime of the item pointer (which, I should note, may become slightly more complicated with stacks, thus providing another argument to use something like Boost) in the stack class along with the implementation of the rest of its behavior. Items that cannot stack are represented by a stack that always contains a single item, and your inventory itself still deals with homogeneous instances of