Search code examples
c++inheritancederived-class

Call function from Derived class stored in a Map with Base class type


I'm trying to make a game engine using Gameobject and Components, similar to Unity. I have a Component Class:

class Component
{
public:
    virtual void DoTheThing(){//Doing the thing};
}

A Texture Class derived from Component, with an overridden function:

class Texture : public Component
{
public:
    void DoTheThing(){//Doing a different thing};
}

A GameObject Class with a Component Map which stores derived components:

class GameObject
{
private:
    map<string, Component> components;
    Texture texture;
    components["id"] = texture;

public:    
    Component getComponent(string id){ return components[id];}
}

And finally:

int main(int argc, char* args[])
{
    GameObject gameObject;
    gameObject.getComponent("id").DoTheThing();
}

What I want is to be able to call the DoTheThing() that exists in the derived class, but it only calls the DoTheThing() in the base class.


Solution

  • Your container is specified to contain Component objects, so when you do components["id"] = texture; you are actually putting a Component object in the map, with the copy constructor invoked on the object texture.

    To ensure polymorphism your container must hold pointers, not a predefined class.

    class Component
    {  public:  virtual void DoTheThing() {cout << "Component\n";} };
    class Texture : public Component
    {  public:  void DoTheThing() override { cout << "Texture\n"; } };
    
    class GameObject
    {   map<string, Component*> components; Texture texture;
        public:
            GameObject() { components["id"] = &texture; }
            Component& getComponent(string id) { return *components[id]; }
            // Remember to return a Component& (or Component*) here, not a
            // Component (by value) because otherwise you would end up with a 
            // base-class Component object copied from the initial Texture
            // object saved in the map.
    };
    
    int main(void)
    {   GameObject gameObject;
        gameObject.getComponent("id").DoTheThing();
        return 0;
    }
    

    OUTPUT: Texture