Я пытаюсь изучить C ++, так что простите меня, если этот вопрос демонстрирует отсутствие базовых знаний, понимаете, факт в том, что мне не хватает базовых знаний.
Мне нужна помощь в разработке итератора для созданного мной класса.
У меня есть класс «Форма», в котором есть контейнер точек. У меня есть класс «Piece», который ссылается на фигуру и определяет позицию для фигуры. Piece не имеет формы, он просто ссылается на форму.
Я хочу, чтобы это выглядело так, как будто Piece - это контейнер точек, которые такие же, как и у формы, на которую он ссылается, но с добавленным смещением позиции Piece.
Я хочу иметь возможность перебирать точки Piece, как если бы Piece был контейнером. Я немного почитал и не нашел ничего, что мне помогло. Буду очень признателен за любые указатели.
Ответы:
Вам следует использовать Boost.Iterators. Он содержит ряд шаблонов и концепций для реализации новых итераторов и адаптеров для существующих итераторов. Я написал статью именно на эту тему ; это в журнале ACCU за декабрь 2008 года. В нем обсуждается элегантное решение (IMO) именно для вашей проблемы: отображение коллекций членов из объекта с помощью Boost.Iterators.
Если вы хотите использовать только stl, в книге Josuttis есть глава о реализации ваших собственных итераторов STL.
источник
/ 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
внутри себя, но тип можно легко адаптировать.источник
auto begin() -> decltype(m_shape.container.begin()) { return m_shape.container.begin(); }
Здесь « Проектирование STL, такого как Custom Container» - отличная статья, в которой объясняются некоторые базовые концепции того, как может быть разработан STL-подобный контейнерный класс вместе с классом итератора для него. Обратный итератор (немного посложнее) оставлен в качестве упражнения :-)
HTH,
источник
Вы можете прочитать эту статью на ddj
По сути, наследуйте от std :: iterator, чтобы большая часть работы выполнялась за вас.
источник
std::iterator
помечен как устаревший .Написание собственных итераторов на C ++ может быть довольно многословным и сложным для понимания.
Поскольку я не смог найти минимального способа написать собственный итератор, я написал этот заголовок шаблона, который может помочь. Например, чтобы сделать
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
.Я надеюсь, что это помогает.
источник
Решением вашей проблемы является не создание собственных итераторов, а использование существующих контейнеров и итераторов STL. Сохраните точки каждой формы в контейнере, таком как вектор.
class Shape { private: vector <Point> points;
Что вы будете делать дальше, зависит от вашего дизайна. Лучший подход - перебирать точки в методах внутри Shape.
for (vector <Point>::iterator i = points.begin(); i != points.end(); ++i) /* ... */
Если вам нужен доступ к точкам за пределами Shape (это может быть признаком несовершенного дизайна), вы можете создать в Shape методы, которые будут возвращать функции доступа итератора для точек (в этом случае также создайте общедоступный typedef для контейнера точек). Посмотрите ответ Конрада Рудольфа, чтобы узнать подробности этого подхода.
источник