Создание собственных итераторов

Я пытаюсь выучить С++, так простите меня, если этот вопрос демонстрирует отсутствие базовых знаний, вы видите, факт в том, что у меня нет базовых знаний.

Мне нужна помощь в том, как создать итератор для созданного мной класса.

У меня есть класс 'Shape', который имеет контейнер Points. У меня есть класс "Piece", который ссылается на Shape и определяет позицию для Shape. Piece не имеет Shape, он просто ссылается на форму.

Я хочу, чтобы это показалось, что Piece является контейнером точек, которые являются такими же, как те, которые используются в Shape, но со смещением позиции Piece.

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

Ответ 1

Вам следует использовать Boost.Iterators. Он содержит ряд шаблонов и концепций для реализации новых итераторов и адаптеров для существующих итераторов. Я написал статью об этой самой теме; это в журнале ACCU в декабре 2008 года. В нем обсуждается элегантное решение (ИМО) для вашей проблемы: выставлять коллекции членов из объекта с помощью Boost.Iterators.

Если вы хотите использовать только stl, книга Josuttis содержит главу о реализации ваших собственных итераторов STL.

Ответ 2

/EDIT: Я вижу, на самом деле здесь нужен собственный итератор (я сначала неправильно понял вопрос). Тем не менее, я даю код ниже, потому что он может быть полезен в подобных обстоятельствах.


Здесь действительно нужен собственный итератор? Возможно, достаточно переслать все необходимые определения в контейнер, содержащий фактические баллы:

// Your class `Piece`
class Piece {
private:
    Shape m_shape;

public:

    typedef std::vector<Point>::iterator iterator;
    typedef std::vector<Point>::const_iterator const_iterator;

    iterator begin() { return m_shape.container.begin(); }

    const_iterator begin() const { return m_shape.container.begin(); }

    iterator end() { return m_shape.container.end(); }

    const_iterator end() const { return m_shape.const_container.end(); }
}

Предполагается, что вы используете vector внутри, но тип может быть легко адаптирован.

Ответ 3

Здесь Разработка STL как Custom Container - отличная статья, в которой объясняются некоторые основные понятия о том, как можно сконструировать STL-класс контейнера наряду с классом итератора для него. Обратный итератор (немного более жесткий), хотя остается в виде упражнения: -)

НТН,

Ответ 4

Вы можете прочитать эту статью статья ddj

В принципе, наследуйте от std:: iterator, чтобы получить большую часть сделанной вами работы.

Ответ 5

Решение вашей проблемы - это не создание собственных итераторов, а использование существующих контейнеров STL и итераторов. Храните точки в каждой форме в контейнере, как вектор.

class Shape {
    private:
    vector <Point> points;

То, что вы делаете с этого момента, зависит от вашего дизайна. Наилучший подход - перебирать точки в методах внутри формы.

for (vector <Point>::iterator i = points.begin(); i != points.end(); ++i)
    /* ... */

Если вам нужно получить доступ к точкам вне Shape (это может быть признаком недостаточного дизайна), вы можете создать в методах Shape, которые возвратят функции доступа итератора для точек (в этом случае также создайте публичный typedef для контейнера точек). Посмотрите на ответ Конрада Рудольфа за подробностями этого подхода.

Ответ 6

Написание пользовательских итераторов на С++ может быть довольно многословным и сложным для понимания.

Так как я не мог найти минимальный способ написания пользовательского итератора, я написал этот заголовок этого шаблона, который может помочь. Например, чтобы сделать класс Piece итерабельным:

#include <iostream>
#include <vector>

#include "iterator_tpl.h"

struct Point {
  int x;
  int y;
  Point() {}
  Point(int x, int y) : x(x), y(y) {}
  Point operator+(Point other) const {
    other.x += x;
    other.y += y;
    return other;
  }
};

struct Shape {
  std::vector<Point> vec;
};

struct Piece {
  Shape& shape;
  Point offset;
  Piece(Shape& shape, int x, int y) : shape(shape), offset(x,y) {}

  struct it_state {
    int pos;
    inline void next(const Piece* ref) { ++pos; }
    inline void begin(const Piece* ref) { pos = 0; }
    inline void end(const Piece* ref) { pos = ref->shape.vec.size(); }
    inline Point get(Piece* ref) { return ref->offset + ref->shape.vec[pos]; }
    inline bool cmp(const it_state& s) const { return pos != s.pos; }
  };
  SETUP_ITERATORS(Piece, Point, it_state);
};

Затем вы сможете использовать его как обычный контейнер STL:

int main() {
  Shape shape;
  shape.vec.emplace_back(1,2);
  shape.vec.emplace_back(2,3);
  shape.vec.emplace_back(3,4);

  Piece piece(shape, 1, 1);

  for (Point p : piece) {
    std::cout << p.x << " " << p.y << std::endl;
    // Output:
    // 2 3
    // 3 4
    // 4 5
  }

  return 0;
}

Он также позволяет добавлять другие типы итераторов типа const_iterator или reverse_const_iterator.

Надеюсь, это поможет.