2010-06-07 102 views
4

有什么是执行下面的迭代器的最好办法一个简单的问题:C++迭代器和继承

说我有一个模板化基类“目录”和两个子类“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。我通过使用包含ListIterator的包装器来解决这个问题,该包装器包含一个ListIteratorImpl指针,该指针包含ListIteratorImpl2和ListIteratorImpl2子类,但这一切都变得非常混乱,尤其是当您需要在ListIterator中实现operator +时。

有关更好的设计来解决这些问题的任何想法?

+0

为什么不使用['std :: advance'](http://www.cplusplus.com/reference/std/iterator/advance/)? – kennytm 2010-06-07 12:02:56

+0

谢谢,但说我需要我提供一个更高效的操作符+而不是仅仅重复使用operator ++。据推测我仍然有同样的问题? – user360366 2010-06-07 12:11:24

+0

前向迭代器('std :: advance()'用于)和随机访问迭代器之间的区别在于前向迭代器没有有效的“操作符+”实现(思考链表)。这个问题意味着一个静态随机访问的迭代器,但它具有访问的动态行为。 – 2010-06-07 12:42:55

回答

5

如果你能逃脱使List<T>::iterator非虚,那么委托的虚拟性关闭添加到列表,使事情变得简单:

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

所以问题是, 实施迭代器 ListImpl1的将是该 为ListImpl2不同。我使用包含一个指向 ListIteratorImpl与子类 ListIteratorImpl2和 ListIteratorImpl2包装的ListIterator 解决此得到了由 ,但它的所有 变得相当混乱,尤其是当 需要实现运营商+在 的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_ 
}; 
+0

这几乎是我目前所拥有的。在ListIterator类中实现operator +的地方更加混乱。因为我需要返回一个新的ListIterator和ListIteratorA/B,我想我需要在ListIteratorInterface中创建一个虚拟的clone()方法来创建一个新的正确类型的impl。 – user360366 2010-06-07 12:17:15

0

你可以存储运营商+作为基类专用虚拟方法,并有迭代器调用。

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

0

说我有一个模板化基类“目录”和两个子类“ListImpl1”和“L istImpl2“

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

+0

只适用于多态性 – user360366 2010-06-14 11:52:56

+0

@jom:有不同种类的多态性。 STL容器基于“编译时多态/静态绑定/通用性/模板”,而不是你想到的那种多态。 – fredoverflow 2010-06-14 15:37:32

+0

我在谈论运行时多态性,即使用列表是一个多实现ListImpl1 和ListImpl2 的接口,对客户端代码透明,但显然这里也存在静态多态。 – user360366 2010-06-18 11:19:03

0

也有一些是迭代器中很重要的,所谓的迭代器类别:

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

每个类别DEF在迭代器中有效支持的一组精确操作。

在这里,你似乎希望拒绝那个强大的身份识别机制来创建某种混合类别,其中的操作都存在,但不能保证它们的效率。

我认为你的设计有异味。

+0

我真的不明白你的意思。它只是一个随机访问迭代器,可以保证时间不变。 – user360366 2010-06-14 11:56:54

+0

然后'operator +'应该是接口的一部分(接受一个有符号的整数作为它的右边参数)。你的问题是什么? – 2010-06-14 17:57:07

+0

问题是operator +正在返回一个迭代器,但是迭代器实现在两个子类中是不同的,所以你必须将这个实现隐藏在'wrapper'迭代器中。我的问题是,是否有更好的方法来做到这一点。 – user360366 2010-06-18 11:24:52