覆盖基类的函数

时间:2016-02-13 15:51:08

标签: c++ inheritance

我在从基类覆盖函数时遇到了一些麻烦。

这是我的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渲染?

4 个答案:

答案 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();
    }
}