2010-06-07 165 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