如何在单个向量中存储不同的类?

时间:2015-08-02 21:00:19

标签: c++ class vector object-slicing

所以我有一个载满我游戏所有物品的载体;玩家对象,敌人对象,墙壁等等......向量中的所有内容都是Framework的子项,所以我创建了向量类型Framework,因为这是与通用数据最接近的东西为他们打字。

问题是它没有从它存储的对象运行被覆盖的函数。所以我用谷歌搜索它,通过将它们存储为Framework来明显地发现我是对象切片。那么我的问题是,如何将所有这些对象存储在一个列表中?

仅供参考,这是调用假定被覆盖函数的地方。

for (vector<Framework>::iterator num = gameObjects.begin(); num != gameObjects.end(); ++num)
{
    //The current thing
    Framework currentObject = *num;
    currentObject.frameEvent();
    currentObject.frameEndEvent();
    currentObject.drawEvent();
}

提前致谢。

7 个答案:

答案 0 :(得分:7)

您必须存储指针(Framework*)或std::shared_ptr< Framework >(可能是std::unique_ptr< Framework >)个实例。这允许使用虚拟调用和late binding - 这意味着当您引用对象时,将在运行时确定要调用的正确函数。别忘了发挥你的作用virtual

然后,你的代码(以类似的方式)

for (vector< Framework* >::iterator num = gameObjects.begin(); num != gameObjects.end(); ++num)
{
  Framework* currentObject = *num;
  currentObject->frameEvent();
  currentObject->frameEndEvent();
  currentObject->DrawEvent();
}

但是,我推荐这样的(需要c ++ 11)

vector< std::unique_ptr< Framework > > gameObjects;

...

for (auto & currentObject : gameObjects)
{
  currentObject->frameEvent();
  currentObject->frameEndEvent();
  currentObject->DrawEvent();
}

无论使用何种类型,最后一个(循环范围)都应该有效(您可以使用普通指针或shared_ptr或unique_ptr,如示例所示)。

如果您有兴趣使用unique_ptr,请注意,为了将这些内容存储在std::vector上,您必须使用std::move,因为只有std::unique_ptr的一个实例1}}(顾名思义)。 Consult this answer如有问题。

答案 1 :(得分:2)

您必须使用std::vector<Framework*>std::vector<std::unique_ptr<Framework>>(或您选择的智能指针)来避免对象切片。

代码示例:

std::vector<std::unique_ptr<Framework>> gameObjects;

gameObjects.push_back(std::make_unique<Player>(/**/));
gameObjects.push_back(std::make_unique<Wall>(/**/));

然后

for (auto& currentObject : gameObjects)
{
    currentObject->frameEvent();
    currentObject->frameEndEvent();
    currentObject->drawEvent();
}

答案 2 :(得分:2)

存储指向Framework的指针,并利用多态性。

// Base class
class Framework {
    // Make pure virtual if nothing is done here.
    virtual void frameEvent(); // = 0;

    // To ensure the derived instances are deleted properly.
    virtual ~Framework(); // = default;
};

// Some specialized class
class SomeObject : public Framework {
    void frameEvent() override; // C++11 style override.
};

std::vector<std::unique_ptr<Framework>> objects;

// Add a new SomeObject to the list
objects.emplace_back(new SomeObject());

答案 3 :(得分:1)

嗯,直接的答案是 - 你不是。或者您将获得已经遇到的对象切片。您需要使用C ++的多态能力并将对象的公共接口存储在向量中。稍后,您可以通过根据实际对象类型调用具有不同实现的接口函数来调用所需的行为。

答案 4 :(得分:1)

您必须在frameEvent中设置frameEndEventdrawEventFramework虚拟。然后,将std::shared_ptr存储在您的向量中:

std::vector<std::shared_ptr<Framework>> objects;
objects.push_back(new GameObject());

for (vector<Framework>::iterator num = gameObjects.begin(); num != gameObjects.end(); ++num)
{
  //The current thing
  const Framework& currentObject = **num; // reference, don't copy anything if you don't need to
  currentObject.frameEvent();
  currentObject.frameEndEvent();
  currentObject.drawEvent();
}

请注意,您可以将unique_ptr存储在向量as long as you don't use operations that require copying elements中。

另一种选择,如果你不能使这些函数虚拟并知道你正在处理什么类型的对象,你可以先强制转换然后调用非虚函数:

const PlayerObject& player = static_cast<const PlayerObject&>(*objects[0]);
player.frameEvent();
player.frameEndEvent();
player.drawEvent();

答案 5 :(得分:1)

您需要将指针存储到您的对象中。如果您有C++11,那么理想情况下您将使用std::unique_ptr存储它们(假设您有一个主矢量)。

<强> C ++ 03

std::vector<Framework*> gameObjects;

for(std::vector<Framework*>::iterator num = gameObjects.begin();
    num != gameObjects.end(); ++num)
{
    (*num)->frameEvent();
    (*num)->frameEndEvent();
    (*num)->drawEvent();
}

C ++ 11

std::vector<std::unique_ptr<Framework>> gameObjects;

for(auto& num: gameObjects)
{
    num->frameEvent();
    num->frameEndEvent();
    num->drawEvent();
}

答案 6 :(得分:0)

将指针存储在向量中,而不是实际的实例中。