如何创建具有未知成员函数的通用容器?

发布于 2024-09-07 22:40:53 字数 601 浏览 1 评论 0原文

我注意到我经常需要容器类。例如,在处理粒子系统时,我创建了一个容器类 Particles,它有一个成员 vector。然后我像 my_articles->draw() 一样调用:Particles* my_articles,并在 Particles.draw() I 迭代器 < code>vector并再次对每个粒子调用 draw()。这同样适用于 update()addforce() 等成员函数。现在,我正在开发一个项目,需要一组 Cube< /code> 我需要调用 tween()moveTowards() 等。

我知道我可以使用模板,但在模板类的情况下,成员函数需要先了解。因为我想检查是否可以创建一个通用类,例如我可以使用我的立方体和粒子集合。

有人以前做过这件事或者可以给我一些建议吗?

亲切的问候, 波勒克斯

I noticed that I'm often in the need of a container class. For example when working on a particle system, I create a container class Particles which has a member vector<Particle*>. Then I call: Particles* my_particles like my_particles->draw(), and in the Particles.draw() I iterator over the vector<Particle*> and call draw() on each of the particles again. The same works for member functions like update(), addforce() etc.. Now, I'm working on a project and need a collection of Cube on which I need to call tween(), moveTowards() etc..

I know I can use template, but in the case of a template class the member functions need to be knows before. As I want to check if I can make a generic class, that I can use for example both my Cubes and Particles collections.

Someone who has done this before or can give me some advice on this?

Kind regards,
Pollux

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

当爱已成负担 2024-09-14 22:40:53

简短的回答是你不能在 C++ 中做到这一点。但是,您可以使用STL算法和容器来包装此行为。

首先,您将 Cube 或 Particle 实例放入 std::vector 或其他容器(就像现在一样)。

然后,您可以将 STL 的 std::for_eachstd::mem_fun

它会导致这样的结果:

  std::vector<Particle*> V;

  V.push_back(new Particle);
  V.push_back(new Particle);
  V.push_back(new Particle);
  V.push_back(new Particle);

  std::for_each(V.begin(), V.end(), std::mem_fun(&Particle::draw));

The short answer is that you can't do this in c++. You can, however, use STL algorithms and containers to wrap this behavior up.

First, you'd put your Cube or Particle instances into a std::vector or other container (like you have now).

Then you'd use STL's std::for_each in combination with std::mem_fun.

It'd result in something like this:

  std::vector<Particle*> V;

  V.push_back(new Particle);
  V.push_back(new Particle);
  V.push_back(new Particle);
  V.push_back(new Particle);

  std::for_each(V.begin(), V.end(), std::mem_fun(&Particle::draw));
嘿哥们儿 2024-09-14 22:40:53

不确定我是否完全理解,但是 for_each STL 算法有帮助吗? http://www.sgi.com/tech/stl/for_each.html

Not sure I definitely understand, but would the for_each STL algorithm help? http://www.sgi.com/tech/stl/for_each.html

信仰 2024-09-14 22:40:53

我读到您问:“我可以制作一个可用于立方体和粒子的通用容器,即使它们具有不同的成员函数?”当然,这是最简单的部分。如果需要,您甚至可以将立方体和粒子放在同一个容器中。如果您正在处理指针,则只需使用 void*

std::vector<void*> objects;
objects.push_back(new Particle(...));
objects.push_back(new Cube(...));

当然,您可以对 void* 做很多事情,除了将它们强制转换回来:

for (i = objects.begin(), i != objects.end(), ++i) {
    void* p = objects[i];
    Particle* particle = dynamic_cast<Particle*>(p);
    if (particle) {
        // do particle stuff
        continue;
    }
    Cube* cube = dynamic_cast<Cube*>(p);
    if (cube) {
        // do cube stuff
    }
}

即使你只将粒子存储在你的向量中,比如说,你仍然需要向下转换才能使用它们:

for (i = objects.begin(), i != objects.end(), ++i) {
    void* p = objects[i];
    Particle* particle = dynamic_cast<Particle*>(p);
    if (particle) {
        // do particle stuff
    } else {
        // error!! I thought someone told me this thing only had Particles...
    }
}

你可以看到,这样做比仅仅将它们存储在单独的向量中要尴尬得多,因为你知道其中每个对象的类型每个向量,并且不必执行运行时向下转换来使用它们。这就是为什么这种容器通常被认为是不良风格的原因。

您在该领域可以考虑的其他可能性是 boost::anyboost::variant,它们适用于指针以外的事物。

I read you asking: "can I make a generic container that can be used for both cubes and particles, even though they have different member functions?" Sure, that's the easy part. You can even put both cubes and particles in the same container if you want. If you're dealing with pointers, you just use void*:

std::vector<void*> objects;
objects.push_back(new Particle(...));
objects.push_back(new Cube(...));

Of course, there's not much you can do with void*s, except cast them back:

for (i = objects.begin(), i != objects.end(), ++i) {
    void* p = objects[i];
    Particle* particle = dynamic_cast<Particle*>(p);
    if (particle) {
        // do particle stuff
        continue;
    }
    Cube* cube = dynamic_cast<Cube*>(p);
    if (cube) {
        // do cube stuff
    }
}

And even if you're only storing Particles in your vector, say, you still have to downcast to work with them:

for (i = objects.begin(), i != objects.end(), ++i) {
    void* p = objects[i];
    Particle* particle = dynamic_cast<Particle*>(p);
    if (particle) {
        // do particle stuff
    } else {
        // error!! I thought someone told me this thing only had Particles...
    }
}

You can see that doing this is much more awkward than just storing them in separate vectors where you know the type of each of the objects in each vector and don't have to perform runtime downcasts to work with them. This is why this kind of container is often considered poor style.

Other possibilities for you to look at in this area are boost::any or boost::variant, which work on things besides pointers.

被你宠の有点坏 2024-09-14 22:40:53

据我了解,这里存在一个设计问题,您想使用相同的接口迭代不同的对象类别(立方体/粒子),但很明显它们不能共享相同的接口,并且如果您真的想要也就是说,您必须在 Particles 和 Cube 的抽象基类上实现 tween() 和 moveTowards(),并且在 Particles 类中不实现任何内容。

As far as I understood, there is a design problem here, you want to iterate over different object categories (Cube/Particle) using the same interface, but it's pretty clear that they couldn't share the same interface, and if you really want that, you must implement the tween() and moveTowards() on the abstract base class of Particles and Cube, and implement nothing in the Particles class.

神经暖 2024-09-14 22:40:53

为了完整起见,还有 valarray,尽管使用的是 vector/for_each是一个更好的解决方案。

For completeness, there is also valarray, though using vector/for_each is a better solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文