Search code examples
c++object-slicing

Object slicing in Inventory system


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


Solution

  • 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);