2008-09-29 3 views
132

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

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

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

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

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

+6

Проводка образца кода поможет описать, что вы делаете лучше, чем просто текст на английском языке. – 2008-09-29 13:20:06

+3

Создание пользовательских итераторов, вероятно, не является базовым, по крайней мере, промежуточным. – ldog 2012-02-14 23:58:21

ответ

41

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

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

59

/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 внутренне, но тип может быть легко адаптирован.

+0

Возможно, он хочет использовать алгоритм STL или функциональные функции в отношении своего класса ... – gbjbaanb 2008-09-29 13:07:02

+2

Исходный вопрос действительно говорит о том, что итератор куска контейнера должен изменять значения при их возврате. Для этого потребуется отдельный итератор, хотя он, вероятно, должен быть унаследован или иным образом получен в основном из оригинала. – workmad3 2008-09-29 13:07:13

1

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

class Shape { 
    private: 
    vector <Point> points; 

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

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

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

13

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

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

19

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

НТН,

0

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

Поскольку я не мог найти минимальный способ написать пользовательский итератор, я написал this template header, который может помочь. Например, чтобы сделать Piece класс Iterable:

#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.

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

Смежные вопросы