Полиморфный итератор на базе итераторов STL
От: Vain Россия google.ru
Дата: 17.11.09 19:10
Оценка:
Надо мне было сделать полиморфный итератор, т.е. чистый интерфейс для итератора, т.к. типы которые итерируются — неизвестны на стадии компиляции. Интерфейс примерно такой:
class MyBaseIterator
{
  virtual ~MyBaseIterator() = 0 {}
  virtual void start(bool asForward = true) = 0;
  virtual void step(bool asForward = true) = 0;
  virtual bool done() const = 0;
  virtual mytype getFoo() const = 0;
  virtual bool seek(int id) = 0;
};

Содержимое конечного класса стало примерно таким:
class CBlablaIterator :
  public MyBaseIterator
{
protected:
  const IterationType*                    m_IterObject;   //Класс, объект которого итерируем по базовому интерфейсу.
  IterationTypeContainer::const_iterator  m_IterObjectIt; //Итератор на контейнер-мембер внутри итерируемого объекта.
  //bool                                    m_asForward;    //Нежелательный параметр, см. далее.

  //...
};

Итерируемый объект примерно такой:
typedef std::blabla ContType; //vector, list, map, etc
class IterationType
{
  friend class CBlablaIterator;
protected:
  //..
  ContType m_IterContainer;

public:
  void CreateBlablaIterator(MyBaseIterator*& pIt) const;
  //...
};

Прочитав это, реализация на одном однонаправленном итераторе оказалась несложной:
void CBlablaIterator::start(bool asForward)
{
  ASSERT(m_IterObject);
  if(m_IterObject)
  {
    if(asForward)
    {
      m_IterObjectIt = m_IterObject->m_IterContainer.begin();
    }
    else
    {
      m_IterObjectIt = m_IterObject->m_IterContainer.rbegin().base();
    }
    //m_asForward = asForward;
  }
}

void CBlablaIterator::step(bool asForward)
{
  ASSERT(m_IterObject);
  if(m_IterObject)
  {
    if(asForward)
    {
      if(m_IterObjectIt != m_IterObject->m_IterContainer.end())
      {
        m_IterObjectIt++;
      }
    }
    else
    {
      ContType::const_reverse_iterator reverseIt = m_IterObjectIt;
      if(reverseIt != m_IterObject->m_IterContainer.rend())
      {
        reverseIt++;
        m_IterObjectIt = reverseIt.base();
      }
    }
    //m_asForward = asForward;
  }
}

Проблема возникла, когда надо было реализовать функцию done. Примерная реализация должна была быть такая:
void CBlablaIterator::done()
{
  ASSERT(m_IterObject);
  if(m_IterObject)
  {
    if(m_asForward) //Требует присутствия нежелательного параметра.
    {
      if(m_IterObjectIt != m_IterObject->m_IterContainer.end())
      {
        return false;
      }
    }
    else
    {
      ContType::const_reverse_iterator reverseIt = m_IterObjectIt;
      if(reverseIt != m_IterObject->m_IterContainer.rend())
      {
        return false;
      }
    }
  }

  return true;
}

Можно ли как-нибудь обойтись без этого m_asForward? Почему итераторы для двунаправленных контейнеров — однонаправленные?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.