【问题标题】:How do I store different classes in a single vector?如何将不同的类存储在一个向量中?
【发布时间】:2015-10-24 22:12:47
【问题描述】:

所以我有一个包含游戏所有对象的向量;诸如玩家对象、敌人对象、墙壁等...向量中的所有事物都是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();
}

提前致谢。

【问题讨论】:

    标签: c++ class vector object-slicing


    【解决方案1】:

    您必须存储指针 (Framework*) 或 std::shared_ptr&lt; Framework &gt; (可能是 std::unique_ptr&lt; Framework &gt;) 实例。这允许使用虚拟调用和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 只能有一个实例(顾名思义) . Consult this answer 如有问题。

    【讨论】:

    • 非常感谢!有效。但只是想知道,-&gt; 是什么?这就是你从类的指针调用函数的方式吗?再次感谢您的帮助!
    • 事实上,当你有一个对象时,你使用(点).,当你有指针(或类似指针的对象 - std::shared_ptrstd::unique_ptr)时使用-&gt;。跨度>
    【解决方案2】:

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

    代码示例:

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

    【讨论】:

      【解决方案3】:

      存储指向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());
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

          您必须在Framework 中将frameEventframeEndEventdrawEvent 设为虚拟。然后,将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();
          

          【讨论】:

          • 嗯,你可以,但是关于复制元素有一些限制。
          • 这些限制实际上可以帮助您了解(声明为唯一!)对象的所有权被复制到哪里,这非常有用,尤其是对于初学者。
          【解决方案6】:

          您需要将 指针 存储到您的对象。如果您有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();
          }
          

          【讨论】:

            【解决方案7】:

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

            【讨论】:

              【解决方案8】:

              另一种可能更快的方法是将它们存储在单独的向量中。由于更高的缓存效率,它可以快 50 倍。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2015-07-13
                • 1970-01-01
                • 2011-07-11
                • 2022-01-22
                • 1970-01-01
                • 2018-07-23
                • 2022-01-13
                相关资源
                最近更新 更多