c++classtemplatestypesentity-component-system

How to get all derived classes from a base class in C++?


I'm implementing a game engine in C++ which uses an ECS (Entity-Component-System).

Each GameObject can have multiple Components (stored in GameObject's std::vector<Component*> _components).

I have a method that allows me to get a Component of a GameObject by specifying the type of Component I want:

// In GameObject.h
template <typename T> T* GetComponent() {
    for (Component* c : _components) {
        if (typeid(*c) == typeid(T)) return (T*)c;
    }
    return nullptr;
}
// In main.cpp
RandomComponent* RC = gameObject.GetComponent<RandomComponent>();

Now let's say I have those Components defined:

class TerrainComponent { /* ... */ }
class PerlinTerrainComponent : public TerrainComponent { /* ... */ }
class FlatTerrainComponent : public TerrainComponent { /* ... */ }
// And possibly many more

And have world GameObjects, which all have a TerrainComponent's derived class attached to it.

My problem is that I would need a way to get the TerrainComponent of a world, like so:

TerrainComponent* TC = world.GetComponent<TerrainComponent>();

And get any type of TerrainComponent attached to the world (which, in reality, will be a TerrainComponent derived class).

Is it possible, in C++, to implement a method that would allow me to do that (get all derived classes of a class), without having to manually update a list of TerrainComponent derived classes?


Solution

  • Assuming these classes are all polymorphic/dynamic (which they need to be to use typeid like this), you can just use dynamic_cast instead:

    template <typename T> T* GetComponent() {
        for (Component* c : _components) {
            if (T *tc = dynamic_cast<T *>(c)) return tc;
        }
        return nullptr;
    }