【问题标题】:Fast and flexible iterator for abstract class抽象类的快速灵活的迭代器
【发布时间】:2011-04-27 00:47:23
【问题描述】:

为了以快速灵活的方式使用数据遍历网格,我设置了一个抽象的模板化 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);
}

};

【问题讨论】:

    标签: c++ stl iterator


    【解决方案1】:

    在解决方案中,begin 和 end 不需要是虚拟的,因为它们只是调用虚拟的 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. begin 和 end 应该创建迭代器
    2. 迭代器需要能够被复制构造并调用operator=。如果您尝试为它们创建一个基类,它们将被强制转换为基类,因此您不能为它们使用 virtual
    3. 要绕过 #2,您可以让迭代器只持有指向迭代器实现的基类的指针。

    【讨论】:

    • 感谢您的明确答复。我确实误解了 BaseIteratorImpl 的主要目标。我确实想要结构迭代器配对。我将 GridDataUniform(和我的其他子类)的迭代器实现为嵌套类(std::iterator<:forward_iterator_tag t> 的子类),并实现了 operator++() 和 operator*() 等方法。但是,我不确定如何以这样的方式构造代码,以便可以进行如下一般调用: GridDataStructure::iterator = someGrid->begin(); // someGrid 是 GridDataUniform 的实例 std::cout
    • 您可能应该将您当前的代码添加到您的问题中,并指出您遇到问题的部分。
    • 我添加了嵌套迭代器类及其方法。希望这能解决问题吗?
    • 现在我知道你要去哪里了,你需要像你指出的问题那样做一个包含 iterImpl 的迭代器。问题是你的基础容器不知道返回类型——所以它必须转发到实际类型。
    • 这就是我迷路的地方。我应该在 GridDataBase 中创建一个嵌套超类,从 std::iterator<:forward_iterator_tag t> 继承它,然后从中继承迭代器吗?
    猜你喜欢
    • 1970-01-01
    • 2021-12-17
    • 1970-01-01
    • 2013-04-07
    • 2018-06-07
    • 2015-02-25
    • 2018-12-01
    • 2018-02-06
    • 2014-02-02
    相关资源
    最近更新 更多