抽象类的快速灵活的迭代器 [英] Fast and flexible iterator for abstract class

查看:105
本文介绍了抽象类的快速灵活的迭代器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In order to traverse grids with data in a fast and flexible way I set up an abstract, templated GridDataStructure class. The data should be accessed by STL iterators. When someone uses the class, he should not worry about which kind of STL iterator is appropriate for a specific subclass.

此问题的解决方案似乎是使用迭代器隐藏内部容器并在基础容器上实现通用操作。但是,我不明白为什么begin()和end()成员不再是虚拟的。接下来我无法弄清楚STL迭代器类的必要方法究竟在哪里(比如operator ++,operator *等)。

A solution to this problem seems to be Using Iterators to hide internal container and achieve generic operation over a base container. However, I do not get why the begin() and end() members are not virtual anymore. Next to that I could not figure out where exactly the necessary methods for the STL iterator class (like operator++, operator* etc.) should be implemented.

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

Could you please have a look whether or not I make a design mistake? Important to me is a flexible design, but not at the cost of performance.

我的班级设计:

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风格访问我的网格容器,例如:

I would like to access my grid container in STL style, like:

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

非常感谢任何帮助。

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

Edit (19.10.10): Added nested iterator class

编辑(20.10.10):添加代码:

Edit (20.10.10): Added code:

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);
}

};


推荐答案

在解决方案中,开始和结束都不需要是虚拟的,因为它们只是调用 BaseIteratorImpl :: begin BaseIteratorImpl :: end 这些是虚拟的。

In the solution, begin and end don't need to be virtual, because they just call BaseIteratorImpl::begin and BaseIteratorImpl::end which are virtual.

在您的具体情况下,您可以只需开始结束虚拟而不做任何转发,它将能够做你想要的。你指出的解决方案是你想要在同一个结构上使用不同的样式迭代器,而不仅仅是你想要的结构 - 迭代器配对。

In your specific case, you could just make begin and end virtual and not do any forwarding and it would be able to do what you want. The solution you pointed to is if you want different style iterators over the same structure, not just structure-iterator pairings which it seems you want.

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

Here's something to start with (not tested or even compiled) -- might not compile and will leak (write destructors, copy ctors, op=, where you need to) -- just to get you started on the idea.

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;
};

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

I typed this directly in to the text area of this answer -- not a compiler. It's meant to give you the idea so you can get started.


  1. 开始和结束应该创建迭代器

  2. 迭代器需要能够被复制构造并且在它们上调用operator =。如果您尝试为它们设置一个基类,它们将被转换为基类,因此您无法使用虚拟它们

  3. 要绕过#2,您只需保留迭代器指向迭代器实现的基类的指针。

这篇关于抽象类的快速灵活的迭代器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆