Как создать универсальный контейнер с неизвестными функциями-членами? - PullRequest
0 голосов
/ 03 июля 2010

Я заметил, что мне часто нужен контейнерный класс.Например, работая над системой частиц, я создаю контейнерный класс Particles, который имеет член vector<Particle*>.Затем я вызываю: Particles* my_particles как my_particles->draw(), и в Particles.draw() I итератор над vector<Particle*> и снова вызываю draw() для каждой из частиц.То же самое работает для функций-членов, таких как update(), addforce() и т. Д. Теперь я работаю над проектом и мне нужен набор Cube, для которого мне нужно вызвать tween(), moveTowards() и т. Д.

Я знаю, что могу использовать шаблон, но в случае класса шаблона функции-члены должны быть известны раньше.Поскольку я хочу проверить, могу ли я создать общий класс, я могу использовать, например, мои коллекции кубов и частиц.

Кто-то, кто делал это раньше или может дать мне несколько советов по этому поводу?

С уважением, Поллукс

Ответы [ 5 ]

4 голосов
/ 03 июля 2010

Короткий ответ: вы не можете сделать это в c ++. Вы можете , однако используйте алгоритмы и контейнеры STL, чтобы обернуть это поведение.

Во-первых, вы должны поместить свои экземпляры Куба или Частицы в std::vector или другой контейнер (как у вас сейчас).

Тогда вы будете использовать STL's std :: for_each в сочетании с std :: 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));
1 голос
/ 03 июля 2010

Я прочитал, что вы спрашиваете: «Могу ли я создать общий контейнер, который можно использовать как для кубов, так и для частиц, даже если у них разные функции-члены?»Конечно, это самая легкая часть.Вы можете даже поместить оба кубика и частиц в один контейнер, если хотите.Если вы имеете дело с указателями, вы просто используете void*:

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

Конечно, вы ничего не можете сделать с void* s, кроме как отбросить их обратно:

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::any или boost::variant, которые работают с другими вещами, кроме указателей.

1 голос
/ 03 июля 2010

Не уверен, что я точно понимаю, но поможет ли алгоритм for_each STL? http://www.sgi.com/tech/stl/for_each.html

0 голосов
/ 04 июля 2010

Для полноты также есть valarray , хотя использование vector / for_each является лучшим решением.

0 голосов
/ 03 июля 2010

Насколько я понял, здесь есть проблема проектирования, вы хотите перебирать разные категории объектов (Cube / Particle), используя один и тот же интерфейс, но совершенно очевидно, что они не могут использовать один и тот же интерфейс, и если Вы действительно этого хотите, вы должны реализовать tween () и moveTowards () в абстрактном базовом классе Particles и Cube и ничего не реализовывать в классе Particles.

...