Создание собственных итераторов
Я пытаюсь выучить С++, так простите меня, если этот вопрос демонстрирует отсутствие базовых знаний, вы видите, факт в том, что у меня нет базовых знаний.
Мне нужна помощь в том, как создать итератор для созданного мной класса.
У меня есть класс '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
.
Надеюсь, это поможет.