从存储在 Base class 类型的 Map 中的 Derived class 调用函数

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

我正在尝试使用类似于 Unity 的游戏对象和组件制作游戏引擎。我有一个组件 Class:

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

派生自组件的纹理 Class,具有覆盖的功能:

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

一个游戏对象 Class 带有存储派生组件的组件映射:

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

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

最后:

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

我想要的是能够调用派生 class 中存在的 DoTheThing(),但它只调用基础 class 中的 DoTheThing()。

问题出在你的GameObjectclass.
让我将其简化为相关部分:

class GameObject {
private:
    map<string, Component> components;

    // ...

public:
    Component getComponent(string id){ /* do something and return a component */ }
};

这里你实际上是在切片你的对象。
这就是调用基础 class 方法的原因。


如果你不知道什么是切片以及如何避免它,我不建议你写一些类似于 Unity 的东西。
我建议您阅读 this Q/A 了解更多详情。

您的容器指定包含 Component 个对象,因此当您这样做时 components["id"] = texture; 您实际上是在映射中放置了一个 Component 对象,并在对象 texture.

上调用了复制构造函数

为确保多态性,您的容器必须包含指针,而不是预定义的 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;
}

输出: 纹理