从存储在 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()。
问题出在你的GameObject
class.
让我将其简化为相关部分:
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;
}
输出:
纹理
我正在尝试使用类似于 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()。
问题出在你的GameObject
class.
让我将其简化为相关部分:
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;
}
输出: 纹理