抽象类的快速灵活的迭代器

时间:2010-10-18 16:02:43

标签: c++ stl iterator

为了以快速灵活的方式遍历带有数据的网格,我设置了一个抽象的,模板化的GridDataStructure类。数据应该由STL迭代器访问。当有人使用该类时,他不应该担心哪种STL迭代器适合于特定的子类。

此问题的解决方案似乎是Using Iterators to hide internal container and achieve generic operation over a base container。但是,我不明白为什么begin()和end()成员不再是虚拟的。接下来,我无法弄清楚应该在哪里实现STL迭代器类的必要方法(如operator ++,operator *等)。

请问您是否犯了设计错误?对我来说重要的是灵活的设计,但不以牺牲性能为代价。

我的班级设计:

template<class T>
class GridDataStructure
{
public:
    virtual iterator begin() = 0;
    virtual iterator end() = 0;
};

template<class T>
class GridDataUniform : GridDataStructure
{
public:
    GridDataUniform(int size);        

    iterator begin();
    iterator end();

    class iterator : public std::iterator<std::forward_iterator_tag, T> {
    public:
      iterator(Node* p) : node_(p) {}
      ~iterator() {}

      iterator& operator=(const iterator& other);
      bool operator==(const iterator& other);
      bool operator!=(const iterator& other);
      iterator& operator++();
      iterator& operator++(int);
      T& operator*();
      T* operator->();

    private:
      Node* node_;
    };

    private:
        T* griddata;
};

我想以STL样式访问我的网格容器,如:

GridDataStructure<int>::iterator = someGrid->begin(); // where someGrid is an instance of GridDataUniform
std::cout << *(iter) << std::endl;

非常感谢任何帮助。

编辑(19.10.10):添加了嵌套迭代器类

编辑(20.10.10):添加了代码:

template<class T>
class GridDataStructureBase
{
protected:
class BaseIteratorImpl
{
    virtual iterator begin() = 0;
    virtual iterator end() = 0;
    virtual iterator& operator++() = 0;
}

public:
class iterator : std::iterator<std::forward_iterator_tag, T>
{
public:
    iterator(const BaseIteratorImpl& itImpl) {}
    iterator begin() { return itImpl->begin(); }
    iterator end() { return itImpl->end(); }
    iterator& operator++() { return itImpl->operator++() }

private:
    BaseIteratorImpl* itImpl;

};

iterator begin()
{
    iterator* i = new iterator(??);
    return i->begin();
}

iterator end()
{
    return iterator(NULL);
}

};

1 个答案:

答案 0 :(得分:4)

在解决方案中,开始和结束不需要是虚拟的,因为他们只是调用虚拟的BaseIteratorImpl::beginBaseIteratorImpl::end

在您的具体情况下,您可以将beginend设为虚拟,不进行任何转发,它就可以执行您想要的操作。你指出的解决方案是你想要在同一个结构上使用不同的样式迭代器,而不仅仅是你想要的结构 - 迭代器配对。

编辑:这是开始的东西(未测试甚至编译) - 可能无法编译并将泄漏(编写析构函数,复制ctors,op =,您需要的地方) - 只是为了让您开始这个想法

template <class T>
class GridIteratorImplBase {
   public:
      virtual GridIteratorImplBase<T>& operator++() = 0;
      virtual T& operator*() = 0;
};

template <class T>
class GridIterator {
   private:
      GridIteratorImplBase<T> *baseImpl;
   public:
      GridIterator(GridIteratorImplBase<T> *b) :baseImpl(b) {}
      GridIterator& operator++() { baseImpl->operator++(); return *this;}
      T& operator*() { return baseImpl->operator*(); }


  // you need to write a dtor, copy ctor and op= or this will leak
  // copy ctor and op= need to make new objects that are copies of baseImpl, dtor needs to delete -- make sure not to share baseImpl between two GridIterator objects
};


template <class T>
class Grid {
   virtual GridIterator<T> begin() = 0;
   virtual GridIterator<T> end() = 0;
};


template <class T>
class GridUniform {

  template <class T>
  class GridUniformIterator : GridIteratorImplBase<T>
      private T* current;
   public:
      GridUniformIterator(T* c) : current(c) {}
      virtual GridIteratorImplBase<T>& operator++() { current++; return *this; }
      virtual T& operator*() { return *current; }
  };

  GridIterator<T> begin() { 
      GridIterator<T> iter(new GridUniformIterator(gridData)); 
      return iter; 
  }
  GridIterator<T> end() { 
      GridIterator<T> iter(new GridUniformIterator(gridData+size));
      return iter; 
  }


  private:
    T* gridData;
    int size;
};

我直接输入到这个答案的文本区域 - 而不是编译器。这意味着给你这个想法,以便你可以开始。

  1. 开始和结束应该创建迭代器
  2. 迭代器需要能够被复制构造并且在它们上调用operator =。如果您尝试为它们创建一个基类,它们将被转换为基类,因此您无法使用虚拟
  3. 要绕过#2,你可以让迭代器保持一个指向迭代器实现的基类的指针。