Okay this is making more sense to me now. Thanks.
I would approach this one of two ways.
1) Polymorphism
Since each type of item will have different logic for their tasks, you can differentiate that logic by putting it in a virtual function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
class Item
{
public:
virtual ~Item() { }
virtual void Use() = 0; // pure virtual 'Use' function - each Item will provide its own implementation
protected:
int price_or_value;
int weight;
int more_properties_common_to_all_items;
};
// different types of items: a book and a potion
class Book : public Item
{
public:
virtual void Use() { /* Use/Read the book here*/ }
protected:
int property_specific_to_books;
};
class Potion : public Item
{
public:
virtual void Use() { /* Use/Drink the potion here*/ }
protected:
int property_specific_to_potions;
};
//.....
void AFunctionThatDoesSomethingWithAnItem( Item* theitem )
{
// we want to use the given item:
theitem->Use(); // <- polymorphism automatically figures out which item we have
// and calls the appropriate Use function. Doesn't matter if it's a Book/Scroll/Potion/whatever.
}
|
Advantages:
- Keeps all item logic in the item class
- Adding new items does not require code changes to be made anywhere but in the new item class
- Allows all Items to be treated as similar types ('Item's), rather than their specific type ('Potion', etc). Makes it easier to throw all of them in a unified container like a vector or list.
Disadvantages:
- Requires a common 'Use' interface for all items. If some items are used differently than others, you'll either have to adjust the Use() function
in all classes so that they can all be called the same way.
2) Clump all items into a single class/struct, and give them an ID as to their type
Here we move the logic outside of the Item class, which probably means it's more suitable to be a struct with possibly a union contained within:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
enum ItemId
{
Book,
Potion
};
struct Item
{
std::string name;
ItemId id;
int price_or_value;
int weight;
int more_properties_common_to_all_items;
union
{
struct
{
int property_specific_to_books;
} book;
struct
{
int property_specific_to_potions;
} potion;
};
};
//...........
void AFunctionThatDoesSomethingWithAnItem( Item* theitem )
{
// we want to use the given item. Figure out what kind of item it is:
switch( theitem->id )
{
case Book: /* Read/Use book here */ break;
case Potion: /* Drink/Use potion here */ break;
}
}
|
Advantages:
- No need to have a common 'Use' interface for all items. Each item can be
Disadvantages:
- Harder to maintain/make additions to because logic is scattered throughout the entire program rather than neatly contained in each Item's class.
...........
It almost sounds to me like you are doing a hybrid of these two styles, which I strongly recommend against doing. Mixing them gives you the weaknesses of each and the benefits of neither.