简体   繁体   中英

Instantiate an Object of Abstract Base Class type using Templates and/or typeof()

I'm trying to rewrite the following C# functionality in C++, but there's now a lot more I need to think about:

public abstract class Component
{
}

public class Entity
{
    private List<Component> m_components = new List<Component>();

    public T AddComponent<T>() where T : Component
    {
        if (typeof(T).IsSubclassOf(typeof(Component)))
        {
            T newComponent = Activator.CreateInstance<T>();
            m_components.Add(newComponent);
            return newComponent;
        }
        else
        {
            return null;
        }
    }

    public Component AddComponent(Type t)
    {
        if (t.IsSubclassOf(typeof(Component)))
        {
            Component newComponent = (Component)Activator.CreateInstance(t);
            m_components.Add(newComponent);
            return newComponent;
        }
        else
        {
            return null;
        }
    }
}

This is as far as I got:

class Component
{
    Component() { }
    ~Component() { }
    void OnCreate() = 0;
}

class Entity
{
public:
    template<class N> void Entity::AddComponent()
    {
        N *newComponent = new N();
        m_components->push_back(newComponent);
        newComponent->OnCreate();
    }

private:
    std::vector<Component*> *m_components;
}

Googling and reading up on templates did some good but at this point I think I need an experienced programmers view on this. Am I on the right tracks? I'm getting 'unresolved external symbol' errors and the C++ code isn't validating that it's creating a subclass of the correct type. I appreciate this might encompass a couple of topics but it would be great if anyone could give me a hand!

I think the right path is to experiment with smart pointers. Here's some sfinae based approach doing somewhat the same thing as you did in your C# solution:

#include <memory>
#include <vector>
#include <type_traits>

class Component {
public:
    Component() { }
    ~Component() { }
    virtual void OnCreate() = 0;
};

class Entity {
public:
    template<class T> std::enable_if_t<std::is_base_of<Component, T>::value> AddComponent() {
        auto inserted = std::make_shared<T>();
        inserted->OnCreate();
        m_components.push_back(std::move(inserted));
    }

    template<class T> std::enable_if_t<!std::is_base_of<Component, T>::value> AddComponent() {
    }
private:
    std::vector<std::shared_ptr<Component>> m_components;
};

class Component1: public Component {
public:
    void OnCreate() { }
};
class Component2: public Component {
public:
    void OnCreate() { }
};
class Component3 {
public:
    void OnCreate() { }
};

int main() {
    Entity e;
    e.AddComponent<Component1>();
    e.AddComponent<Component2>();
    e.AddComponent<Component3>(); // won't add anything to your entity
                                  // as Component3 is not a subclass of
                                  // Component
}

[live demo]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM