-1

I'm working on an inventory system for a game and I'm hitting a brick wall with object slicing; I'm losing variables on a reference to a derived class. Below is an excerpt in which a T-shirt is created in the main game file, and then passed to a players inventory for storage. However only the variables present in the base class Item are preserved.

game.cpp

#include "Item.h"
#include "Clothes.h"
#include "Shirts.h"

shirt_item white_shirt = shirt_item(materialDescriptor::cotton, colourDescriptor::white);

player.getComponent<InventoryComponent>().storeItem(&whiteShirt);

InventoryComponent.cpp

bool InventoryComponent::storeItem(Item *inItem)
{
    if (freeInvSpace() > 0)
    {
        items.push_back(inItem);
        return true;
    }
    else if (freeInvSpace() < 0)
    {
        std::cout << "ERROR! Inventory over filled somehow" << std::endl;
    }

    return false;
}

InventoryComponent.h

#pragma once
#include "Components.h"

#include "Item.h"
#include "Clothes.h"
#include "Shirts.h"



class InventoryComponent : public Component // Entity component system
{
public:
    std::vector<Item*> items;

   InventoryComponent(int inSize)
    {
        size = inSize;
    }

    bool storeItem(Item *inItem);
...
}

Item.h

#pragma once
#include <string>

class Item
{
public:
    std::string name,
        description;

    bool pronoun;
};

Clothes.h

#pragma once
#include <vector>
#include <string>

#include "Item.h"
#include "materialDescriptor.h"
#include "colourDescriptor.h"

class Clothes : public Item
{
public:
    materialDescriptor material;
    std::vector<bodyParts> coverage;
    colourDescriptor colour;

    Clothes(std::string inName, std::string inDescription, materialDescriptor inMaterial, colourDescriptor colour, bool inPronoun = false)
    {
        name = inName;
        description = inDescription;
        material = inMaterial;
        pronoun = inPronoun;
    }

    Clothes() {} 
};

Shirts.h

#pragma once
#include "Clothes.h"
#include "materialDescriptor.h"
#include "colourDescriptor.h"

class shirt_item : public Clothes
{
public:
    shirt_item(materialDescriptor inMaterial, colourDescriptor inColour)
    {
        material = inMaterial;
        colour = inColour;
        description = "A basic shirt that covers the wearer from the elements";
        name = "T-Shirt"
    }
}

ECS.h

#pragma once
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
#include <bitset>
#include <array>

#include "Components.h"

class Component
{
public:
    Entity* entity;

    virtual void init() {}
    virtual void update() {}
    virtual void draw() {}

    virtual ~Component() {}

private:
};

class Entity
{
private:
    bool active = true;
    std::vector<std::unique_ptr<Component>> components;

    ComponentArray componentArray;
    ComponentBitSet componentBitSet;

public:
    template <typename T> T& getComponent() const
    {
        auto ptr(componentArray[getComponentTypeID<T>()]); 
        return *static_cast<T*>(ptr);
    }
}

Using Vs2019 break points, the constructor for the T-shirt works but as soon as I attempt to use the object it is boiled down to it's base class: Item > Clothes > Shirts

  • 2
    Please show a [mre], where are you using the stored item? How do you know object slicing is occurring? – Alan Birtles Mar 09 '20 at 06:29
  • 2
    Please make your example a [mre]. `game.cpp` is not a valid translation unit, and so you likely omit a detail that helps explain what you did wrong. – StoryTeller - Unslander Monica Mar 09 '20 at 06:29
  • @AlanBirtles I've been using the run-time object explorer in VS19 to examine the player's inventory and the stored pointer points to the T-shirt object missing anything defined in Clothes.h and Shirts.h Now that say it like that, I'll certainly attempt to work with the variable when I get the chance in about an hour. I wonder if VS19 is misrepresenting the variable to me – Natharantos Mar 09 '20 at 06:41
  • I suspect `player.GetComponent` is where the problem is, would you be able to add the code for that? (unrelated `<= 0` is probably important in InventoryComponent.cpp.) – Jeff Foster Mar 09 '20 at 06:45
  • Three debugger isn't always able to work out the derived class for a base class pointer so only shows the base class variables – Alan Birtles Mar 09 '20 at 06:46
  • 1
    @JeffFoster Actually if you think about `<= 0`, it is correct. If it equals zero, that is the normal state of full inventory and the function just returns false. I thought it error at first too. – Jan Hošek Mar 09 '20 at 07:06
  • Object slicing typically happens when base class object is constructed or assigned from derived class object. It can be that some container of base class objects is attempted to be filled with derived class objects. Hard to tell. You show wrong parts of your code. – Öö Tiib Mar 09 '20 at 07:11

1 Answers1

1

If you pass and store inherited objects through pointers you eventually have to store them on the heap. Instead you are creating them on the stack. Just do
auto white_shirt = std::make_unique<shirt_item>(materialDescriptor::cotton, colourDescriptor::white);

Jan Hošek
  • 187
  • 1
  • 9
  • How would I make ```InventoryComponent::storeItem()``` take any derived ```item``` as a parameter once I'm working with unique pointers? – Natharantos Mar 09 '20 at 09:08
  • You can pass unique pointers to derived classes as unique pointers to the base class. `bool storeItem(std::unique_ptr inItem);` works as you'd expect. – Jan Hošek Mar 09 '20 at 09:12