Search code examples
c++pointerspolymorphismdowncast

Comparing types between derived classes


I am making the engine for a game and I can't seem to solve the following problem.

So, I have a base component class from which all the different components are derived. A GameObject is basically a container for different components. The components are stored in a vector containing pointers to the base component class. Now I need the GameObject class to have a getComponent member function template that will return the component with the requested type from the vector.

To be more clear:

class Component 
{
        /..../
};

class RigidBody : Component
{
        /..../
};

class Animation : Component
{
        /..../
};

class GameObject
{
public:
        template <class T>
        T* getComponent();

        void addComponent(Component*);
private:
        std::vector<Component*> m_components;
};

/...../

GameObject test;
test.AddComponent(new RigidBody());
test.AddComponent(new Animation());
Animation * animation = test.getComponent<Animation>();

Or something among those lines.

For simplicity's sake say that the vector is guaranteed to have the component that we are looking for and that there are no components of the same type.

Since the pointers in the vector are of the base component type, how can I check if they originally were of the requested type? Thanks in advance!


Solution

  • Assuming that Component has at least one virtual function (otherwise what's the point of inheriting from it, right?) you should be able to do what you need using Runtime Type Information (RTTI) and dynamic_cast, like this:

    template <class T> T* getFirstComponent() {
        for (int i = 0 ; i != m_components.size() ; i++) {
            T *candidate = dynamic_cast<T*>(m_components[i]);
            if (candidate) {
                return candidate;
            }
        }
        return nullptr;
    }
    

    Recall that dynamic_cast<T*> would return a non-null value only when the cast has been successful. The code above goes through all pointers, and picks the first one for which dynamic_cast<T*> succeeds.

    Important note: While this should do the trick at making your program do what you want, consider changing your design: rather than pulling out objects by type, give them virtual functions that would let you use them all in a uniform way. It is pointless to put objects of different classes into one container, only to pull them apart at some later time. RTTI should be used as the last resort, not as a mainstream tool, because it makes your program harder to understand.

    Another valid approach would be to store the individual components separately, not in a single vector, and get the vector only when you need to treat the objects uniformly.

    Less important note: if nullptr does not compile on your system, replace with return 0.