Reputation: 109
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
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
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