unique_ptr can't instantiate class because it's abstract

I have an abstract class(Component)
and this class should be owned by another class(GameObject).
Every GameObject has a vector of components.

Header:

 class Component;
        class GameObject{
        public:
            GameObject();
            virtual ~GameObject();
            void addComponent(std::unique_ptr<Component> component);
            void addComponent(Component* component);
        void removeComponent(std::unique_ptr<Component> component);

        virtual void update();
        std::string getInfo();
        
        //return the first component of type T
        template<typename T>
        T* getComponent(){
            for(auto& component : components){
                if(dynamic_cast<T*>(component.get())){
                    return dynamic_cast<T*>(component.get());
                }
            }
            return nullptr;
        }

        // return the component with the type T
        template<typename T>
        std::vector<T*> getComponents(){
            std::vector<T*> components;
            for(auto component : this->components){
                if(dynamic_cast<T*>(component)){
                    components.push_back(dynamic_cast<T*>(component));
                }
            }
            return components;
        }

        
        std::vector<std::unique_ptr<Component>> components;

    };
class Component
    {
    private:
    public:
        Component() = delete;
        virtual ~Component() = 0;
        virtual std::string getInfo();
        
        
        //the game object this component is attached to
        GameObject* gameObject;
        
    };

source:

std::string GameObject::getInfo() {
    std::stringstream ss;
    ss << typeid(*this).name();
    for (Uint32 i = 0; i < this->components.size(); i++) {
        ss << typeid(components[i]).name() << " " << this->components[i]->getInfo();
    }
}


void GameObject::addComponent(std::unique_ptr<Component> component) {
    components.push_back(std::move(component));
}
void GameObject::addComponent(Component* component) {
    components.push_back(std::move(std::make_unique<Component>(*component)));
}
void GameObject::removeComponent(std::unique_ptr<Component> component) {
    for (auto it = components.begin(); it != components.end(); it++) {
        if (it->get() == component.get()) {
            components.erase(it);
            return;
        }
    }
}

ERROR: cannot instantiate abstract class. file: memory line 3416

>Solution :

Your issue is here:

void GameObject::addComponent(Component* component) {
    components.push_back(std::move(std::make_unique<Component>(*component)));
}

When you dereference component, as far as the compiler knows you still just have a Component, not the actual instantiation–it can’t call the proper copy constructor.

The solution is to just deleted this member function entirely. You already have a version that takes a std::unique_ptr<Component>, so require the user of GameObject to provide the unique_ptr in all cases.

Leave a Reply