Как правильно обрабатывать полиморфизм с векторами класса в C ++? - PullRequest
0 голосов
/ 28 апреля 2019

В настоящее время я внедряю систему компонентов сущностей и работаю над способом сохранения векторов компонентов, каждый вектор одного типа компонентов должен быть смежным, поэтому я использую vector<Component>*, а не vector<Component*>. Я новичок в C ++ и пришел из Java, поэтому я все еще борюсь с некоторыми концепциями, касающимися разметки памяти и полиморфизма.

Я полностью реализовал (казалось бы) рабочую версию этого. У меня есть вектор для каждого типа компонента (например, PositionComponent, GravityComponent и т. Д.), Потому что компоненты отличаются по размеру. Но так как количество типов не известно во время компиляции, мне нужен вектор указателей для указания на эти ComponentLists разных типов. Я использую reinterpret_casts с картой, которая отслеживает типы компонентов для достижения этой цели, но должен быть менее неопределенный способ сделать это. (Надеюсь!)

Вот картина того, чего я хочу достичь: Компоновка списка компонентов

Редактировать: я просто замечаю, что моя программа падает с ошибкой сегментации после return 0 в основной функции. Стек вызовов кажется поврежденным, так как он переходит на какой-то случайный адрес, а не возвращается. Так что моя система определенно несовершенна.

Основная функция:

int main(int argc, char** argv)
{
    EntityComponentSystem ecs;

    // Fill with some components
    for(int i = 0; i < 5; ++i)
    {
        ecs.addComponent(AComponent());
        ecs.addComponent(BComponent());
        ecs.addComponent(CComponent());
    }

    // Print all components
    std::cout << "Components: " << std::endl;

    // Print AComponents
    std::cout << "A Components: " << std::endl;
    ComponentList<AComponent>* aComps = ecs.getComponentList<AComponent>();
    aComps->print();

    // Print BComponents
    std::cout << std::endl << "B Components: " << std::endl;
    ComponentList<BComponent>* bComps = ecs.getComponentList<BComponent>();
    bComps->print();

    // Print CComponents
    std::cout << std::endl << "C Components: " << std::endl;
    ComponentList<CComponent>* cComps = ecs.getComponentList<CComponent>();
    cComps->print();

    return 0;
}

Класс EntityComponentSystem:

class EntityComponentSystem
{
    private:
        // To shorten some things up
        typedef std::vector<ComponentList<Component>*>::iterator                    ComponentListIterator;
        typedef std::unordered_map<std::type_index, Component::TypeID>::iterator    MapIterator;

        std::vector<ComponentList<Component>*>                  comps;          // Indexed by TypeID
        std::unordered_map<std::type_index, Component::TypeID>  componentMap;   // Maps typeid(Component) to TypeID

    public:
        EntityComponentSystem() : comps(), componentMap() {}
        ~EntityComponentSystem()
        {
            for(ComponentListIterator it = comps.begin(); it < comps.end(); ++it)
            {
                delete (*it);
            }
        }

        template<typename T>
        void addComponent(const T& component)
        {
            static_assert(std::is_base_of<Component, T>::value, "T must be of type Component!");

            MapIterator found = componentMap.find(typeid(T));
            ComponentList<T>* componentList = nullptr;

            if(found == componentMap.end()) // This component derivative hasn't been added yet, so add it
            {
                componentList = new ComponentList<T>();
                int componentId = comps.size();
                this->comps.push_back(reinterpret_cast<ComponentList<Component>*>(componentList));
                this->componentMap[typeid(T)] = componentId;
            }
            else
            {
                componentList = reinterpret_cast<ComponentList<T>*>(comps[found->second]);
            }

            componentList->push(component);
        }

        template<typename T>
        ComponentList<T>* getComponentList()
        {
            Component::TypeID id = getComponentTypeId<T>();
            if(id == Component::TYPE_ID_UNKNOWN) return nullptr;
            return reinterpret_cast<ComponentList<T>*>(comps[id]);
        }

        template<typename T>
        Component::TypeID getComponentTypeId()
        {
            static_assert(std::is_base_of<Component, T>::value, "T must be of type Component!");

            MapIterator found = componentMap.find(typeid(T));

            if(found == componentMap.end())
            {
                return Component::TYPE_ID_UNKNOWN;
            }

            return found->second;
        }
};

Класс ComponentList:

template<typename T>
class ComponentList
{
    private:
        std::vector<T>      components;

    public:
        void push(const T& t)
        {
            this->components.push_back(t);
        }

        void print()
        {
            for(typename std::vector<T>::iterator it = components.begin(); it != components.end(); ++it)
            {
                it->test();
            }
        }
};

Класс базовых компонентов и его производные:

class Component
{
    public:
        typedef uint16_t    TypeID;
        static const TypeID TYPE_ID_UNKNOWN = -1;

        virtual ~Component() = default;

        virtual void test()
        {
            std::cout << "I'm the base!" << std::endl;
        }
};

class AComponent : public Component
{
    private:
        static int  nextValue;
        int     someValue;      // To test if different sizes of Component derivatives cause any problems!

    public:
        AComponent()
        {
            this->someValue = nextValue++;
        }

        void test()
        {
            std::cout << "I'm AComponent! Value: " << someValue << std::endl;
        }
};

int AComponent::nextValue = 0;

class BComponent : public Component
{
    public:
        void test()
        {
            std::cout << "I'm BComponent!" << std::endl;
        }
};

class CComponent : public Component
{
    public:
        void test()
        {
            std::cout << "I'm CComponent!" << std::endl;
        }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...