C ++迭代器和继承

时间:2010-06-07 11:58:24

标签: c++ inheritance templates iterator

快速询问以下实现迭代器的最佳方法:

假设我有一个模板化基类'List'和两个子类“ListImpl1”和“ListImpl2”。基类的基本要求是可迭代的,即我可以做到:

for(List<T>::iterator it = list->begin(); it != list->end(); it++){
   ...
}

我还想允许添加迭代器,例如:

for(List<T>::iterator it = list->begin()+5; it != list->end(); it++){
   ...
}

所以问题是ListImpl1的迭代器的实现将与ListImpl2的迭代器的实现不同。我通过使用包含指向ListIteratorImpl的指针的包装器ListIterator来解决这个问题,该指针包含子类ListIteratorImpl2和ListIteratorImpl2,但它们都变得非常混乱,特别是当您需要在ListIterator中实现operator +时。

有关更好的设计以解决这些问题的想法吗?

5 个答案:

答案 0 :(得分:5)

如果你可以让List<T>::iterator非虚拟化,那么将虚拟化委托添加到List会让事情变得简单:

template<typename T>
class List
{
    virtual void add_assign(iterator& left, int right) = 0;

public:
    class iterator
    {
        const List* list;
        const T* item;
    public:
        iterator(const List* list, const T* item) : list(list), item(item) {}

        iterator& operator +=(int right)
        {
            list->add_assign(*this, right);
            return *this;
        }
        static iterator operator +(iterator const& left, int right)
        {
            iterator result = left;
            result += right;
            return result;
        }
    };

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

否则(如果迭代器需要存储明显不同的数据),那么你必须执行常规的,无聊的指针实现来获得虚拟性:

template<typename T>
class List
{
    class ItImpl
    {
        virtual ItImpl* clone() = 0;
        virtual void increment() = 0;
        virtual void add(int right) = 0;
    };
public:
    class iterator
    {
        ItImpl* impl;
    public:
        // Boring memory management stuff.
        iterator() : impl() {}
        iterator(ItImpl* impl) : impl(impl) {}
        iterator(iterator const& right) : impl(right.impl->clone()) {}
        ~iterator() { delete impl; }
        iterator& operator=(iterator const& right)
        {
            delete impl;
            impl = right.impl->clone();
            return *this;
        }

        // forward operators to virtual calls through impl.
        iterator& operator+=(int right)
        {
            impl->add(right);
            return *this;
        }
        iterator& operator++()
        {
            impl->increment();
            return *this;
        }
    };
};

template<typename T>
static List<T>::iterator operator+(List<T>::iterator const& left, int right)
{
    List<T>::iterator result = left;
    result += right;
    return result;
}

template<typename T>
class MagicList : public List<T>
{
    class MagicItImpl : public ItImpl
    {
        const MagicList* list;
        const magic* the_magic;
        // implement ...
    };
public:
    iterator begin() const { return iterator(new MagicItImpl(this, begin_magic)); }
    iterator end() const { return iterator(new MagicItImpl(this, end_magic)); }
};

答案 1 :(得分:1)

迭代器中有一些非常重要的东西,叫做Iterator Category:

  • InputIterator的
  • 输出迭代
  • ForwardIterator
  • BidirectionalIterator
  • RandomAccessIterator的

每个类别定义迭代器高效支持的一组精确操作。

在这里,您似乎希望拒绝强大的识别机制来创建某种类型的混蛋类别,其中操作都存在,但不保证其效率。

我认为你的设计有气味。

答案 2 :(得分:0)

  

所以问题在于   迭代器的实现   ListImpl1将与此不同   对于ListImpl2。我绕过这个   使用包装器ListIterator   包含指向a的指针   带有子类的ListIteratorImpl   ListIteratorImpl2和   ListIteratorImpl2,但都是   变得非常混乱,特别是在   你需要在中实现operator +   的ListIterator。

这个设计很好恕我直言,我看不出任何有关它的东西。除了相等和减法之外,迭代器的操作可以通过虚函数很容易地实现,所以你会有像

这样的东西。
class ListIteratorInterface // abstract
{
protected:
  virtual Data& operator*()=0;
  // and other operations
};
class ListIteratorA;
class ListIteratorB; // implementation of the above
class ListIterator
{
  ListIteratorInterface* impl_;
public:
  // when you create this, allocate impl_ on the heap
  // operations, forward anything to impl_
};

答案 3 :(得分:0)

您可以将operator +作为私有虚方法存储在基类中,并使用迭代器调用。

或者,您可以考虑静态多态列表类,而不是运行时多态性。

答案 4 :(得分:0)

  

假设我有一个模板化基类'List'和两个子类“ListImpl1”和“ListImpl2”

在这里使用继承你到底获得了什么?