0

So I'm currently working on a little summer project here -- a text-based RPG (I know -- how original!). Anyways, I've run into an issue. I want to have an inventory class for my character, which contains an array of pointers to different items. The issue is that these items will be of many different class types in themselves (weapon, quest, misc., etc.). So I'm wondering if there's a way that I can make a pointer that can switch between types? Or is my thinking completely wrong? Thanks. --Simon Ward

Little Boy Blue
  • 311
  • 4
  • 17
  • You should implement some sort of more general object like a generic Inventory_Object that anything "inventoryable" inherits from. Then make your array of that type. – brian Jun 18 '18 at 03:23
  • Open the chapter in your C++ book that explains how to use the `std::variant` template, and start reading it. – Sam Varshavchik Jun 18 '18 at 03:23

4 Answers4

1

If all your item classes inherit from a common ancestor (eg. an Item class) you will be able to have a vector of Item *. This can be a good time to use polymorphism as well:

#include <iostream>
#include <vector>

class Item {
public:
  virtual const char *name() const = 0;
  virtual void use() = 0;
};

class Knife : public Item {
public:
  const char *name() const override { return "Knife"; }
  void use() override { std::cout << "Using the knife" << std::endl; }
};

class Laser : public Item {
public:
  const char *name() const override { return "Laser"; }
  void use() override { std::cout << "Using the laser" << std::endl; }
};

int main() {
  std::vector<std::unique_ptr<Item>> v;
  v.emplace_back(std::make_unique<Knife>());
  v.emplace_back(std::make_unique<Laser>());

  for(const std::unique_ptr<Item> &i : v) {
    std::cout << "Name: " << i->name() << std::endl;
    i->use();
  }

  return 0;
}

Output:

$ c++ --std=c++14 m.cpp
Name: Knife
Using the knife
Name: Laser
Using the laser
cfillion
  • 1,340
  • 11
  • 16
1

Inheritance should work well for this. All you have to do is create one base class(parent class), that, for example a type(what type of class it is supposed to be-Weapon, quest, misc). Every itemType class will inherit from this parent class, and when you store all these items, you store them with the objectType as the parent class and then when you're reading an item, you look at it's type, cast it to the appropriate class type and then do what you need to with it.

class parentItem
{
public:
    parentItem(string) : type(string) {};
    string type; //Doesn't have to be a string, could be an enum or anything you want
}

class weapon : public parentItem
{
    weapon() : parentItem("Weapon"){};
    weaponInfo wInfo;
    int damageDeals;
}

Then somewhere else in your code when you're accessing one of these from the inventory

parentItem item = player.getWeapon() // Just generic code, just grabbing the object
Weapon* sword;
if(parentItem.type = "Weapon")
{
    sword = (Weapon*)item
}
sword->attack(); //or whatever you want to do with it

TLDR: Use inheritance on every item class so that they can all be considered 1 type and then cast them to the appropriate type when you need to access the information of the child class

Kenny Castro
  • 121
  • 11
  • Oooh, ok; I was wondering about this. So if I create an array of pointers to a parent class, can I make those pointers point to any children of that parent as well? – Little Boy Blue Jun 19 '18 at 04:59
  • Yeah, they remain objects of the child class but they're stored and accessed as the parent class, so when you need something in the child class that's not in the parent class, you type cast it to the appropriate type – Kenny Castro Jun 19 '18 at 05:02
1

You could have a array (or std::vector) of type classX, now derive all carryable items from classX. See also Vector that can have 3 different data types C++ . Here is an extremely simplified example:

#include <string>
#include <vector>
#include <iostream>

class Carryable {
public:
    virtual std::string info()=0;
};

class Potion: public Carryable {
public:
    std::string name;
    int mana;
    std::string info() { return "potion - name["+name+\
       "] mana["+std::to_string(mana) + "]"; };
};

class Book: public Carryable {
public:
    std::string title;
    std::string author;
    std::string info() { return "book - title["+title+"] author["+author+"]"; };
};

main() {
    std::vector<Carryable*> inventory;
    Potion p;
    p.name="Dragon breath";
    p.mana=40;
    inventory.push_back( &p );
    Book b;
    b.title="Wisdom of Chu";
    b.author="Wen Chu";
    inventory.push_back( &b );
    for (int i=0;i<inventory.size();i++) {
        std::cout << "inventory item " << i << ":";
        std::cout << inventory[i]->info() << "\n";
    }
}

output:

don@oysters:~/proj/src$ ./a.out 
inventory item 0:potion - name[Dragon breath] mana[40]
inventory item 1:book - title[Wisdom of Chu] author[Wen Chu]
don bright
  • 1,113
  • 1
  • 11
  • 15
1

I know that you can solve your problem by using Object Oriented Programming as 3 answers of Kenny Castro, don bright and cfillion. However, void pointer also is a solution. I know it is not a good idea but it also can solved your problem and I want introduce it for you. My demo code as follow:

#include<iostream>
using namespace std;
//assume you just have 3 item type
class A
{
public:
    void func(){
       cout<<"I am A object\n";
    }
};

class B
{
public:
     void func(){
        cout<<"I am B object\n";
     }
};

class C
{
public:
     void func(){
        cout<<"I am C object\n";
     }
};

int main()
{
  //assume that you have 5 items of three types
  void* items[5];
  char type[5];  //if items[i] is A object then type[i] = 'A'
                 //if items[i] is B object then type[i] = 'B'
                 //if items[i] is C object then type[i] = 'C'
   //When you insert item into array, let's mark 'A', 'B', or 'C' for each item
   items[0]=new A, type[0]='A';
   items[1]=new B, type[1]='B';
   items[2]=new C; type[2]='C';
   items[3]=new B, type[3]='B';
   items[4]=new A, type[4]='A';

   for(int i=0;i<5;i++) 
   {
     if(type[i]=='A'){
        ((A*)items[i])->func();
     }
     if(type[i]=='B'){
        ((B*)items[i])->func();
     }
     if(type[i]=='C'){
        ((C*)items[i])->func();
     }
   }
   return 0;
}

OUTPUT:

I am A object I am B object I am C object I am B object I am A object

TaQuangTu
  • 2,155
  • 2
  • 16
  • 30