Итератор для пользовательского контейнера с производными классами - PullRequest
3 голосов
/ 03 февраля 2010

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

    class Vector 
    {
       virtual Iterator begin() = 0;
       virtual Iterator end () = 0 ;

    ... // some more functions.
    } ;

    class VectorImplA : public Vector
    {
       Iterator begin() { return m_data.begin() ; }
       Iterator end () { return m_data.end() ; }
    private:
       SomeFloatContainer m_data ;
    } ;

    class VectorImplB : public Vector
    {
       Iterator begin() { return m_data.end() ; }
       Iterator end() ; { return m_data.end() ; }


    private:
        std::vector <float> m_data ;

    } ;

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

Ответы [ 3 ]

7 голосов
/ 03 февраля 2010

Я и раньше сталкивался именно с этой проблемой. Хотя существуют способы решения вашей проблемы, вам, скорее всего, следует отказаться от идеи векторного базового класса. То, что вы, вероятно, должны делать вместо этого, это имитировать способ, которым сконструирован контейнер c ++ STL.

STL состоит из концепций , а не базовых классов. std::vector является моделью концепции Container, но не наследуется от базового класса Container. Концепция - это набор требований, которых должна придерживаться любая модель концепции. См. эту страницу для требований к Container, например.

Требования для Container указывают, например, что вы должны ввести typedef типа содержимого контейнера как value_type, а итераторы typedef как iterator и const_iterator. Кроме того, вы должны определить функции begin() и end(), возвращающие итераторы, и т. Д.

Затем вам нужно будет изменить функции, которые работают с вашим базовым классом Vector, чтобы вместо этого работать с любым классом, который соответствует требованиям, налагаемым концепцией. Это можно сделать, сделав функции шаблонными. Вам не обязательно придерживаться концепций, используемых STL, вы также можете придумать свои собственные. Следование концепциям, определенным в STL, дает дополнительное преимущество, заключающееся в том, что алгоритмы STL (например, std::sort) могут работать с вашими контейнерами.

Быстрый пример:

class VectorImplA
{
public:
    typedef VectorImplAIterator iterator;

    iterator begin();
    iterator end();
};

class VectorImplB
{
public:
    typedef VectorImplBIterator iterator;

    iterator begin();
    iterator end();
};

template <typename VectorConcept>
void doSomeOperations(VectorConcept &container)
{
    VectorConcept::iterator it;
    it = container.begin();
}

int main()
{
    VectorImplA vecA;
    VectorImplB vecB;
    doSomeOperations(vecA); // Compiles!
    doSomeOperations(vecB); // Compiles as well!
}

В качестве бонуса, чтобы ответить на исходный вопрос, рассмотрим следующий дизайн (хотя я бы не пошел по этому пути!):

struct IteratorBase
{
    virtual void next() = 0;
};

struct IteratorA : IteratorBase
{
    void next() {};
};

struct IteratorB : IteratorBase
{
    void next() {};
};

class Iterator
{
    IteratorBase *d_base;
public:
    void next() { d_base->next(); }
};
0 голосов
/ 30 марта 2011

Я сталкивался с такой же проблемой раньше. Я использовал решение № 2 с небольшими изменениями в определении класса Iterator

class Iterator :public boost::iterator_facade<Iterator,element_type, forward_traversal_tag>
{
  ...
}

Таким образом, я смог использовать алгоритмы STL с моими контейнерами.

0 голосов
/ 03 февраля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...