我在从基类覆盖函数时遇到了一些麻烦。
这是我的GameObject类:
namespace GameEngine {
class GameObject {
public:
virtual void render() {
std::cout << "Render Game Object" << std::endl;
}
};
}
这是我的Player类:
class Player : public GameEngine::GameObject {
public:
void render() {
std::cout << "Render Player" << std::endl;
}
};
在MainComponent.cpp中我有一个GameObjects的Vector,我循环遍历它们来渲染它们
Player player;
vector<GameEngine::GameObject> gameObjects;
void MainComponent::init() {
gameObjects.push_back(player);
gameLoop();
}
void MainComponent::render() {
for(int i = 0; i < gameObjects.size(); i++) {
gameObjects[i].render();
}
}
我希望这段代码输出“Render Player”,因为gameObjects向量中唯一的对象是Player,但它输出“Render Game Object”。有没有办法可以强制gameObjects向量中的Player对象使用Player渲染而不是GameObject渲染?
答案 0 :(得分:2)
如果使用指针或对基数的引用处理派生类 class,对重写的虚函数的调用会调用 派生类中定义的行为。
您必须将指向基类的指针存储为向量中的基础对象值。
Player player;
vector<GameEngine::GameObject*> gameObjects;
void MainComponent::init() {
gameObjects.push_back(&player);
gameLoop();
}
void MainComponent::render() {
for(int i = 0; i < gameObjects.size(); i++) {
gameObjects[i]->render();
}
}
答案 1 :(得分:1)
您的向量包含GameObject
个值。因此,将子类实例推送到此向量中会对对象进行切片:https://en.m.wikipedia.org/wiki/Object_slicing
您应该使用GameObject
指针,或者最好使用shared_ptr<GameObject>
答案 2 :(得分:1)
这是一个更简单的代码版本,说明了同样的问题:
GameEngine::GameObject object = player;
object.render();
问题是player
对象通过切除GameObject
的基本部分而转换为player
。所以存储的是GameObject
,而不是Player
对象。
解决方案是使用指针或引用而不是对象:
GameEngine::GameObject *ptr = &player;
ptr->render();
您需要在gameObjects
中执行相同的操作:不应存储GameObject
类型的对象,而应存储指向GameObject
的指针:
std::vector<GameEngine::GameObject*> gameObjectPointers;
gameObjectPointers.push_back(&player);
gameObjectPointers[0]->render();
一旦你这样做,你必须密切注意对象的生命周期。如果在player
之前gameObjectPointers
被销毁,那么gameObjectPointers[0]
将指向一个不再存在的对象,使用它会使坏事发生。
答案 3 :(得分:1)
有没有办法可以强制gameObjects向量中的Player对象使用Player渲染而不是GameObject渲染?
没有。您声明vector
类型为vector<GameEngine::GameObject> gameObjects;
,因此基类'实例将存储在vector
中。当gameObjects.push_back(player);
,对象为slicing copied时,没有Player
。
您可以将基类的指针存储到vector
中,最好使用智能指针来避免手动内存管理。例如:
vector<unique_ptr<GameEngine::GameObject>> gameObjects;
void MainComponent::init() {
gameObjects.emplace_back(new Player);
// or gameObjects.push_back(unique_ptr(new Player));
gameLoop();
}
void MainComponent::render() {
for(int i = 0; i < gameObjects.size(); i++) {
gameObjects[i]->render();
}
}