【问题标题】:Iteration over every object in a class迭代类中的每个对象
【发布时间】:2011-12-01 02:12:30
【问题描述】:

由于我正在制作的游戏的性质,我需要能够在运行中随机创建对象。我需要能够每秒 60 次更改一个类的所有当前存在的对象的变量。

有人告诉我,尽管 C++ 无法反射,但我可以将对象的地址传递给向量。不幸的是,我对如何做到这一点有点困惑。有更好的解决方案吗?如果没有,有人可以提供示例代码吗?

tl;博士?我需要对类中所有对象的变量运行一个函数。怎么做?

【问题讨论】:

  • 你需要用通用的方式来做吗?含义:您知道要操作的对象的类型还是模板参数?否则我不明白你为什么需要在这里反思。
  • 您需要更详细地描述您想要做什么。最好的方法取决于你正在做什么样的改变。您可能希望将对象存储在容器中,或者您可能只需要一个静态成员变量,具体取决于您想要实现的目标。
  • 我将主要做的是更新每个对象中精灵的位置和旋转。

标签: c++ class object foreach iteration


【解决方案1】:

“将对象的地址传递给向量”听起来像这样

std::vector<MyObject *> objectAddresses;

这是一个指向 MyObject 的指针向量。请注意,您必须手动添加和删除指针。删除对象时未能从该向量中删除对象的指针很容易导致程序崩溃。

根据性能需求,您可能希望选择除矢量以外的 STL 容器。向量将使您的迭代速度非常快,但是从向量中的任意位置移除一个对象会很昂贵。如果不首先知道它在向量中的位置,它也会很困难。考虑 std::set。

http://www.cplusplus.com/reference/stl/列出了stl提供的容器,并大致描述了它们的性能。

一旦有了指针容器,只需对每个条目进行 for 循环并调用函数。您可能需要取消引用两次,例如(*itor)->func().

也许这只是你的术语,但我有不止一个对象,而且 我对这将如何工作感到困惑。介意进一步深入吗? 我认为它应该更符合 std::vector objectAddresses;

如果你声明class MyClass,你应该说vector&lt;MyClass*&gt;。如果您声明class MyObject,请说vector&lt;MyObject*&gt;。对编译器来说也是一样的,所以使用对你来说更易读的那个。

std::vector 并不是大多数图形程序员所认为的向量(例如,3 个值表示 3d 空间中的位置)。它是一个自调整大小的数组。因此,当您向向量添加值时(通过 push_back 方法),它会检查是否已分配足够的内存来保存附加值,并在必要时重新分配更大的内存块。

class MyClass
{
  public:
    static std::vector<MyClass *> objAddrs;
    MyClass()
    {
      objAddrs.push_back(this);
    }
    ~MyClass()
    {
      // Find this in objAddrs & objAddrs.erase()
    }

    void doWork()
    {
      // something useful here
    }
};

将导致 MyClass 的每个实例在构造时将其自己的地址添加到 objAddrs 的末尾。请记住,析构函数必须删除相同的地址!

for(std::vector<MyObject *>::iterator itor=MyClass::objAddrs.begin(); itor!=MyClass::objAddrs.end(); ++itor)
{
  (*itor)->doWork();
}

将对 MyObject() 的每个现有实例调用 doWork() 函数。如果任何 MyObjects 已被销毁并且析构函数无法删除它们,则将取消引用悬空指针并调用未定义的行为(可能是段错误)。

std::set 允许您按值删除:

class MyClass
{
  public:
    static std::set<MyClass *> objAddrs;
    MyClass()
    {
      objAddrs.insert(this);
    }
    ~MyClass()
    {
      objAddrs.erase(this);
    }
};

【讨论】:

  • 也许这只是你的术语,但我有不止一个对象,我对它如何工作感到困惑。介意进一步深入吗?我认为它应该更像 std::vector objectAddresses;
  • 详细说明太长,无法发表评论,因此我已将其编辑为答案。
  • 感谢您的信息,这是非常有用的东西。我从没想过以这种方式使用类:)
【解决方案2】:

我假设您想找到一种方法来遍历 a 的所有实例 当前存在的类而无需经历麻烦 自己管理存储。 SelfStore 旨在作为基础 此类功能的类。它在内部使用list,因为我 假设对象经常被创建和删除。你可能想要 切换到更适合您用例的另一种存储类型。这 迭代器被保留为快速删除的成员,但可以完成 没有额外的存储空间是否有问题。这还需要一些 (很多)调整,例如私有存储和静态beginend,没有 可变访问,通过 typedef 隐藏存储类型等。它是 不是线程安全的。 SelfStore 只是一个模板,因为它可能会出现 好用。

#include <iostream>
#include <list>

template<typename T>
class SelfStore
{
  typename std::list<SelfStore*>::iterator it;

public:
  SelfStore() {
    store.push_back(this);
    it = --end(store);
  }

  virtual ~SelfStore() {
    store.erase(it);
  }

  static std::list<SelfStore*> store;
};

template<typename T>
std::list<SelfStore<T>*> SelfStore<T>::store = std::list<SelfStore<T>*>();


struct Foo : public SelfStore<Foo> {

};


int main()
{
  {
  Foo f, g, h;
  std::cout << SelfStore<Foo>::store.size() << std::endl;
  }

  Foo a, b;
  std::cout << SelfStore<Foo>::store.size() << std::endl;
  return 0;
}

【讨论】:

    【解决方案3】:

    除非您将对象放在容器中,否则您不能对数据成员使用标准迭代器或迭代循环。

    我建议创建一个visitor 方法,该方法接受一个函子并将其应用于每个数据成员。

    在 Stack Overflow 上搜索访客设计模式。

    【讨论】:

      【解决方案4】:

      在对象的构造函数中,将它们添加到全局静态对象列表中(记得在析构函数中删除对象!)。这将让您找到对象并操纵它们。如果您的程序是多线程的,您将需要一种方法来同步访问列表和您正在操作的对象。

      【讨论】:

        猜你喜欢
        • 2018-04-05
        • 2014-04-03
        • 1970-01-01
        • 2015-11-28
        • 1970-01-01
        • 2016-05-07
        • 2015-01-19
        • 1970-01-01
        • 2019-06-23
        相关资源
        最近更新 更多