#include <cstdlib>
#include <ctime>
#include <iostream>
#include <string>

struct Item
{
    Item(const std::string& name) : _name(name) {}
    std::string getName() const { return _name; }

    virtual ~Item() {}

private:
    std::string _name;
};

struct Weapon : public Item
{
    Weapon(const std::string& name, int damage) : Item(name), _damage(damage) {}

    void setDamage(int dam) { _damage = dam; }
    int getDamage() const { return _damage; }

private:

    int _damage;
};

struct Special : public Item
{
    Special(const std::string& name, const std::string& otherProperty)
        : Item(name), _other(otherProperty) {}

    std::string getOther() const { return _other; }

private:
    std::string _other;
};

int main()
{
    std::srand(std::time(0));

    for (unsigned i = 0; i < 10; ++i)
    {
        Item* iptr;
        switch (std::rand() % 3)
        {
        case 0: iptr = new Weapon("Axe", 6); break;
        case 1: iptr = new Special("Deodorant", "Feminine"); break;
        case 2: iptr = new Item("Generic"); break;
        default: std::cout << "Unexpected value encountered\n"; return 0;
        }

        // how do we know what we've got here?  Is it a Special?  A Weapon?  Just a generic Item?
        if (Weapon* w = dynamic_cast<Weapon*>(iptr))
        {
            std::cout << "We have a weapon with name: " << w->getName();
            std::cout << "\nand damage: " << w->getDamage() << '\n';
        }
        else if (Special* s = dynamic_cast<Special*>(iptr))
        {
            std::cout << "We have a special with name: " << s->getName();
            std::cout << "\nand property: " << s->getOther() << '\n';
        }
        else
            std::cout << "We have an item with name: " << iptr->getName() << '\n';
            
        delete iptr;
    }
}