Stein121
Stein121

Reputation: 109

How to make a console inventory system dynamic

I have an inventory system that stores "Item" types which is an abstract class. I have a derived class called "Skates". The program allows the user to add "Skates" into a vector of "Item" pointers. The user input the model and ID of the skates and I create a "Skates" object with those as the parameters. Then I use an "Item" pointer to point to that "Skates" object and add it into the vector. When the user wants to edit the "Skates" object I have to dynamic_cast it back to a "Skates" object and then edit it.

std::vector<Item*> ItemCollection;
Item * item = new Skates("model1", 1);
ItemCollection.push_back(item);
//To retrieve it
Skates * skatesToEdit = dynamic_cast<Skates*>(ItemCollection[0]);

The problem I am facing now is to account for a new derived class, "Skateboard" class for example. I don't want to create a new method to handle the editing of the "Skateboard" class like:

Skateboard * skateboardToEdit = dynamic_cast<Skateboard*>(ItemCollection[0]);

Since this would mean that everytime I make a new derived class I need to write this same style of code everytime. So I would like to know if there is a way to make the application dynamically know what derived class it is without me needing to specify it. So it needs to be able to determine the datatype and then prompt the user to edit whatever property it has (since the goal is for users to edit the object in the first place) in one dynamic method which I think should be impossible.

Upvotes: 1

Views: 356

Answers (2)

user2512323
user2512323

Reputation:

As I understand, you have methods for editing your derived items, like void editSkates(Skates*), void editSkateboard(Skateboard*) etc.

Then you can apply Visitor pattern. Create abstract Visitor class with visit method, overloaded for every distinct Item subclass:

class ItemVisitor{
public:
    virtual void visit(Skates*) = 0;
    virtual void visit(Skateboard*) = 0;
    //... one function for every subclass
};

Create virtual void accept(ItemVisitor&) = 0; method in your Item class. In every subclass, say, Skates, override this method to call the correct visit:

void Skates::accept(ItemVisitor& visitor){
    visitor.visit(this);
}

Now you can inherit ItemVisitor to do specific things with specific subclasses, like so:

class EditVisitor: public ItemVisitor{
public:
    virtual void visit(Skates* skates){
        skates->editSpecialSkatesProperty();
    }

    virtual void visit(Skateboard* skateboard){
        skateboard->editSpecialSkateboardProperty();
    }
};

And finally do this specific thing with your generic Item * item instance:

EditVisitor edit;
item->accept(edit);

Upvotes: 0

Andrey
Andrey

Reputation: 60075

I would suggest that maybe inheritance is not what you need here. Instead of having classes like Skates, Skateboard, consider having just class Item, which is collection of key values representing properties. This way you don't really care about class of the item and you can list and edit properties dynamically.

Upvotes: 1

Related Questions