Подтвердить что ты не робот

Написание собственной реализации stl-подобного Iterator в С++

В настоящее время я пытаюсь понять внутренности итераторов на разных языках, то есть способ их реализации.

Например, существует следующий класс, отображающий интерфейс списка.

template<class T>
class List
{

    public:

    virtual void Insert( int beforeIndex, const T item ) throw( ListException ) =0 ;
    virtual void Append( const T item ) =0;   

    virtual T Get( int position ) const throw( ListException ) =0;
    virtual int GetLength() const =0;

    virtual void Remove( int position ) throw( ListException ) =0;


    virtual ~List() =0 {};
};

Согласно GoF, лучший способ реализовать итератор, который может поддерживать разные виды обхода, - создать базовый класс Iterator (friend of List) с защищенными методами, которые могут получить доступ к элементам List. Конкретные реализации Iterator будут обрабатывать задание по-разному и получить доступ к личным и защищенным данным List через базовый интерфейс.

С этого момента все становится запутанным. Скажем, у меня есть класс LinkedList и ArrayList, оба производные от List, и есть также соответствующие итераторы, каждый из классов возвращается. Как я могу реализовать LinkedListIterator? Я абсолютно вне идей. И какие данные могут получить базовый класс итератора из списка (который является простым интерфейсом, в то время как реализации всех производных классов значительно отличаются)?

4b9b3361

Ответ 1

В STL не используются абстрактные базовые классы и виртуальные функции. Вместо этого он сознательно разработан, чтобы не быть OO (в смысле GoF) и полностью построен на шаблонах, нацеленных на "полиморфизм времени компиляции". Шаблоны не заботятся об абстрактных интерфейсах. Вещи работают до тех пор, пока они имеют достаточно похожий интерфейс (например, если вы должны были вызвать Append push_back вместо этого, для вас будет работать больше кода, ожидающего соответствия STL-контейнеров, например std::back_insert_iterator).

Итератору, совместимому с STL, придется перегружать множество операторов, чтобы вести себя как указатель (насколько это возможно, учитывая ограничения контейнера), включая *, ->, ++, -- ( если двунаправленный - дважды связан), == и !=.

Ответ 2

Стандартная библиотека С++ не использует полиморфизм и наследование при реализации итераторов; вместо этого он использует метапрограммирование шаблона С++ и понятие (но не формальный синтаксис *) "понятий".

По существу, он будет работать, если интерфейс для вашего класса итератора будет соответствовать некоторому набору требований. Этот набор требований называется "концепцией". Существует несколько различных концепций итератора (см. эту страницу для списка всех из них), и они являются иерархическими. Основы создания совместимого итератора С++ - это сделать ваш интерфейс соответствующим понятию. Для простого итератора, который идет только в прямом направлении, это потребует:

  • typedef value_type для значения, которое является результатом разыменования вашего итератора.
  • typedef reference_type, который является ссылочным типом для соответствующего типа значения.
  • typedef pointer, который является типом указателя для соответствующего типа значения.
  • typedef iterator_category, который должен быть одним из input_iterator_tag, forward_iterator_tag, bidirectional_iterator_tag или random_access_iterator_tag, в зависимости от вашего механизма обхода.
  • typedef difference_type, указывающий результат вычитания двух разных итераторов.
  • Функция A const value_type& operator*()const для разыменования итератора.
  • A value_type& operator*(), если ваш итератор может использоваться для управления значением.
  • Функции увеличения (operator++() и operator++(int)) для поиска вперед.
  • Функция разности: difference_type operator-(const type_of_iterator&)

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

* Стандартная библиотека С++ использует понятия так часто неформально, что коммиты стандартов на С++ пытались ввести формальный механизм объявления их на С++ (в настоящее время они существуют только в документации стандартной библиотеки, а не в каких-либо явных код). Однако постоянные разногласия в предложении привели к тому, что он был заменен на С++ 0x, хотя после этого он, скорее всего, будет пересмотрен для стандарта.