C++迭代器继承

3
My requirements are the same as those asked in the question "Using Iterators to hide internal container and achieve generic operation over a base container"[1] on Stack Overflow. I have a generic pure virtual base container class, which needs to provide an iterator that is STL-compliant so that I can use it with #include <algorithm> in C++ algorithms. My implementation uses only a single class instead of two classes, as in the [1] solution. Base pure virtual class:
class BaseItr
{
  public:
    class iterator : public std::iterator<std::input_iterator_tag, int>
    {
      public:
        iterator() : _in(NULL) {}
        inline iterator(const iterator& org) : _in(org._in) {}
        inline iterator& operator=(const iterator& other) { _in = other._in; return *this; }
        virtual inline int operator * () { return _in->operator*(); }
        virtual inline iterator& operator++() { (*_in)++; return *this; }
        virtual inline iterator& operator++(int unused) { (*_in)++; return *this; }
        virtual inline bool operator==(const iterator& other) 
        {
          return *(*_in) == *(*(other._in));
        }
        virtual inline bool operator!=(const iterator& other)
        {
          return *(*_in) != *(*(other._in));
        }
        // would use shared pointer insted of this
        //~iterator() { if(_in) { delete _in; } }
        static inline iterator New(iterator *in) { return iterator(in); }
      private:
        iterator(iterator *in) : _in(in) {}
        iterator *_in;
    };

    virtual iterator begin() = 0;
    virtual iterator end() = 0;
};

实现

class Itr : public BaseItr
{
  private:
    class iterator : public BaseItr::iterator
    {
      public:
        iterator(int val) : _val(val), BaseItr::iterator() {}
        int operator * () { return _val; }
        inline iterator& operator++() { ++_val; return *this; }
        inline iterator& operator++(int unused) { _val++; return *this; }
      private:
        int _val;
    };
    BaseItr::iterator _begin;
    BaseItr::iterator _end;
  public:
    inline Itr(int start, int end)
    {
      _begin = BaseItr::iterator::New(new iterator(start));
      _end = BaseItr::iterator::New(new iterator(end));
    }

    BaseItr::iterator begin() { return _begin; }
    BaseItr::iterator end() { return _end; }
};

我的实现是有效的,我想知道这种实现有没有任何缺点,请帮助我决定使用适当的实现来设计。我在github上添加了完整的工作示例代码:https://gist.github.com/3847688 参考:
1个回答

5
最明显的问题是,您的迭代器没有值语义。
STL算法可以自由复制迭代器。例如,假设:
template <typename It>
It find(It b, It e, typename std::iterator_traits<It>::const_reference t) {
    for (; b != e; ++b) {
        if (*b == t) { return b; }
    }
    return e;
}

问题在于,如果你使用 BaseItr& 调用此算法,则结果的类型为 BaseItr,因此您会遇到未定义行为,这就是所谓的对象切片
为了给您的迭代器提供值语义,您需要在抽象实现周围创建一个包装类,并通过虚拟的 clone 方法正确地管理复制。如果您的迭代器最终具有虚拟方法,则您正在错误地进行操作。

如果迭代器是抽象实现的包装器,我们是否仍然面临“对象切片”问题?因为我们可以在没有抽象类实例的情况下初始化包装器,如果是这样,如何防止它。我们可以使用std::unique_ptr代替虚拟的clone吗? - Kam
2
如果你的迭代器最终使用了虚方法,那么你的做法是错误的。如果可以的话,我会给这个点赞多次。 - ildjarn
1
@Kam:std::unique_ptr 处理所有权,clone 处理复制。你可以同时使用两者。 - Matthieu M.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接