简体   繁体   English

迭代类中的每个对象

[英]Iteration over every object in a class

Due to the nature of a game I am making, I need to be able to create objects at random on the fly. 由于我正在制作的游戏的性质,我需要能够随意创建对象。 I need to be able to change the variables of all currently existing objects of a class 60 times a second. 我需要能够每秒60次更改类的所有当前现有对象的变量。

I've been told that although C++ is incapable of reflection, I would be able to pass the addresses of objects to a vector. 我被告知虽然C ++无法反射,但我可以将对象的地址传递给向量。 Unfortunately, I'm just a little bit confused as to how to do that. 不幸的是,我对如何做到这一点感到有些困惑。 Is there a better solution? 有更好的解决方案吗? If not, can someone provide example code? 如果没有,有人可以提供示例代码吗?

tl;dr? TL;博士? I need to run a function on the variables of all the objects in a class. 我需要对类中所有对象的变量运行一个函数。 Howdo? Howdo?

"Pass the address of an object to a vector" sounds like this “将对象的地址传递给矢量”听起来像这样

std::vector<MyObject *> objectAddresses;

This is a vector of pointers to MyObject. 这是指向MyObject的指针向量。 Note that you have to add and remove the pointers manually. 请注意,您必须手动添加和删除指针。 Failure to remove an object's pointer from this vector when it is deleted can easily crash your program. 删除对象的指针时,如果删除它,则很容易导致程序崩溃。

Depending on performance needs, you may want to choose an STL container other than vector. 根据性能需求,您可能希望选择除矢量之外的STL容器。 Vectors will make your iteration very fast, but removing an object from an arbitrary position in the vector will be expensive. 向量将使您的迭代非常快,但从向量中的任意位置移除对象将是昂贵的。 Without first knowing its position in the vector, it will also be difficult. 如果不首先知道它在矢量中的位置,那也很困难。 Consider std::set. 考虑std :: set。

http://www.cplusplus.com/reference/stl/ lists the containers provided with stl, and roughly describes their performance. http://www.cplusplus.com/reference/stl/列出了随stl提供的容器,并粗略描述了它们的性能。

Once you have your container of pointers, simply for-loop over each entry and call the function. 一旦你有了指针容器,只需在每个条目上循环并调用该函数。 You will probably need to dereference twice eg (*itor)->func(). 您可能需要解除引用两次,例如(* itor) - > func()。

Maybe it's just your terminology, but I have more than one object, and I'm confused as to how this would work. 也许这只是你的术语,但我有不止一个对象,我对这是如何工作感到困惑。 Mind going further into depth? 介意进一步深入? I'm thinking it should be more along the lines of std::vector objectAddresses; 我认为它应该更符合std :: vector objectAddresses;

If you declare class MyClass , you should say vector<MyClass*> . 如果声明class MyClass ,则应该说vector<MyClass*> If you declare class MyObject , say vector<MyObject*> . 如果声明class MyObject ,请说vector<MyObject*> It will be the same to the compiler, so use whichever is more readable to you. 它与编译器相同,因此请使用更易读的方法。

The std::vector is not what most graphical programmers think of as a vector (eg 3 values signifying a position in 3d space). std :: vector不是大多数图形程序员所认为的向量(例如3个值表示3d空间中的位置)。 It is a self-resizing array. 它是一个自调整大小的数组。 So as you add values to a vector (through the push_back method) it will check to see if it has allocated enough memory to hold the additional values, and re-allocate a larger block of memory if necessary. 因此,当您向向量添加值(通过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
    }
};

Will cause every instance of MyClass to add its own address to the end of objAddrs at construction. 将导致MyClass的每个实例在构造时将其自己的地址添加到objAddrs的末尾。 Remember that the destructor must remove that same address! 请记住,析构函数必须删除相同的地址!

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

Will call the doWork() function on every existing instance of MyObject(). 将在MyObject()的每个现有实例上调用doWork()函数。 If any MyObjects have been destroyed & the destructor fails to remove them, a dangling pointer will be dereferenced & undefined behavior will be invoked (probably a segfault). 如果任何MyObjects被销毁并且析构函数无法删除它们,则将取消引用悬空指针并调用未定义的行为(可能是段错误)。

std::set lets you remove by value: std :: set允许您按值删除:

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

I assume that you want to get a way to iterate over all instances of a class that are currently in existence without going through the hassle of managing the storage yourself. 我假设您想要一种方法来迭代当前存在的类的所有实例,而无需自己管理存储的麻烦。 SelfStore is intended as a base class for such functionality. SelfStore旨在作为此类功能的基类。 It uses a list internally because I assume that objects are created and deleted often. 它在内部使用list因为我假设经常创建和删除对象。 You might want to switch to another storage type that suits your usecase better. 您可能希望切换到另一种更适合您的用例的存储类型。 The iterator is kept as a member for fast removal but could be done without if the extra storage is a problem. 迭代器保留为快速删除的成员,但如果额外的存储是个问题,则可以不进行迭代。 This still needs some (alot) tweaking, eg private storage and a static begin end , no mutable access, hiding of the storage type through typedefs etc. It is not threadsafe. 这仍然需要一些(很多)调整,例如私有存储和静态begin end ,没有可变访问,通过typedef等隐藏存储类型。它不是线程安全的。 SelfStore is only a template because it might come in handy. 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;
}

In the constructor of your objects add them to a global, static list of objects (remember to remove the object in the destructor!). 在对象的构造函数中,将它们添加到全局的静态对象列表中(记住要删除析构函数中的对象!)。 That will let you find the objects and manipulate them. 这将让你找到对象并操纵它们。 If your program is multithreaded you will need a way to sychronize access to the list and the object you are manipulating. 如果您的程序是多线程的,则需要一种方法来同步对列表和您正在操作的对象的访问。

Unless you have your objects in a container, you can't use a standard iterator or iteration loop over your data members. 除非您将对象放在容器中,否则不能对数据成员使用标准迭代器或迭代循环。

I suggest creating a visitor method that takes a functor and applies it to each data member. 我建议创建一个visitor方法,它接受一个仿函数并将其应用于每个数据成员。

Search Stack Overflow for Visitor design pattern. 搜索访问者设计模式的堆栈溢出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM