2009-11-21 64 views
5

好的,所以我現在有兩個使用迭代器的(完全不相關的,不同的項目)類。一個有iteratorreverse_iterator按預期工作,另一個,當前有iterator和一個半分開的const_iterator(具體地說,因爲const_iterator從迭代器派生,代碼LinkedList<int>::iterator i = const_list.begin()是有效的,並且允許您修改const定義的列表...) 。
我打算把所有四種類型添加到這個類...如果我可以。如何將DRY原理應用於C++中的迭代器? (iterator,const_iterator,reverse_iterator,const_reverse_iterator)

我將如何繼續最小化複製/粘貼代碼並僅更改返回類型?創建一個基類,如base_iterator繼承?創建一個iteratorconst_iterator並從那繼承?繼承一些std :: class?如果這些案例中的任何一個都是「最好」的方法,那麼代碼在哪裏?
也許沒有其他選擇是好的?我很迷茫,找不到很多參考資料。

任何意見是讚賞,但請記住,我是新來的主題(通常迭代器和C + +,特別是OOP)。我已經試過了,用於研究GCC附帶的頭文件 - 它們並不完全是我正在尋找的教程。

+0

STDLIB實現的,一般情況差的選擇,從學習,任何語言。他們經常需要處理外部接口(例如操作系統,其他語言),可能需要向後兼容過去十年的代碼,以及其他一些不適用於您的因素。總之:他們不是以教學爲目標。一本好書是必須的,它會爲你提供更好的服務。 – 2009-11-21 21:28:35

回答

3

有時候,所謂的DRY規則(Don't Repeat Yourself,對於那些不熟悉的人)的全面應用並不是最好的方法。特別是如果你對語言(C++和迭代器)和OOP本身(方法論)不熟悉,那麼嘗試最大限度地減少需要編寫的代碼量幾乎沒有什麼好處。

我會實現兩個迭代器使用適當的代碼爲他們每個人。也許在使用語言,工具和技術方面的更多經驗後,然後回去查看是否可以通過找出通用代碼來減少代碼量。

+0

你有沒有必要重複DRY的定義,以至於你現在反射式地做呢? :P – 2009-11-21 21:24:51

+0

可能是合理的建議,我接受了。我做了兩個獨立的基類,迭代器和const_iterator(std :: iterator的兩個子類),以及iterator上的reverse_iterator和reverse_iterator上的const_reverse_iterator。迭代器的總行數達到〜70-75。對4種不同類型不壞。這是排除即將到來的內聯文檔,但包括足夠的空白,使其可讀性。:) – exscape 2009-11-22 19:33:12

+0

雖然「首先實現,稍後重構」似乎是很好的*一般*建議,但這個答案看起來像是一個實現迭代器的協議,它應該是衆所周知的,哪些代碼經常被複制。雖然'iterator'和'reverse_iterator'在實現上可能有很大的不同,'iterator'和'const_iterator' *應該大部分是相同的(至少對於任何理智的實現來說)。 – jamesdlin 2017-08-21 18:07:04

0

LinkedList<int>::iterator i = const_list.begin()你的開始方法是什麼樣的?通過研究STL,你可以看到,容器定義了兩個這樣的方法具有以下特徵:

const_iterator begin() const; 
iterator begin(); 

你不應該有一種讓合格爲const對象的iterator問題。我不認爲DRY適用於此。

+0

他目前(不正確)的const_iterator是從迭代器派生的,所以對於開始的常規const/non-const重載,他的代碼仍然能夠隱式地將任何const_iterator轉換爲迭代器。 – 2009-11-21 21:22:03

1

使迭代器從const_iterator派生而不是其他方式。適當地使用const_cast(作爲實施細節,未暴露給用戶)。這在「迭代器是const_iterators」的簡單情況和模型中可以直接使用。

當這個開始要求在您的代碼澄清註釋,然後編寫單獨的類。您可以使用本地化的宏來生成類似的代碼對你來說,避免重複的邏輯:

struct Container { 
#define G(This) \ 
This& operator++() { ++_internal_member; return *this; } \ 
This operator++(int) { This copy (*this); ++*this; return copy; } 

    struct iterator { 
    G(iterator) 
    }; 
    struct const_iterator { 
    G(const_iterator) 
    const_iterator(iterator); // and other const_iterator specific code 
    }; 
#undef G 
}; 

,宏觀的作用域/本地化是非常重要的,當然,只有使用它,如果它實際上有助於你—如果它會導致可讀性較差的代碼,顯式輸出它。

而關於反向迭代器:在許多情況下,您可以使用std::reverse_iterator來包裝「正常」迭代器,而不是重寫它們。

struct Container { 
    struct iterator {/*...*/}; 
    struct const_iterator {/*...*/}; 

    typedef std::reverse_iterator<iterator> reverse_iterator; 
    typedef std::reverse_iterator<const_iterator> const_reverse_iterator; 
}; 
0

一旦我用下面的方法:

  1. 做一個模板類common_iterator
  2. 添加類型定義爲 「迭代」 和 「常量性」
  3. 添加到 「common_iterator」 構造回吐「迭代器「類型

對於」迭代器「,額外的構造函數將替換默認的複製構造函數uctor,在我的情況下,它相當於默認的拷貝構造函數。

對於「常量性」這將是一個額外的構造函數,它允許從「迭代」

3

它實際上是非常簡單的構建「爲const_iterator」。

首先,看看Boost.Iterator庫。第二:你需要聲明一個基類(在例子中說明了如何繼續),它將與這個類相似。

template <class Value> 
class BaseIterator: boost::iterator_adaptor<...> {}; 

您執行操作來移動指針。請注意,因爲它是對現有迭代器的改編,所以只需幾個筆劃就可以實現它。這真的令人印象深刻。

第三,你只需用const和非const版本的typedef它:

typedef BaseIterator<Value> iterator; 
typedef BaseIterator<const Value> const_iterator; 

庫顯式地告訴你如何讓const_iterator版本是從iterator版構造的。

四,反向的事情,有一個特殊的reverse_iterator對象,這是建立在一個普通的迭代器和向後移動:)

總而言之,在定義迭代器的一個真正優雅,但功能齊全方式自定義類。

我經常編寫我自己的容器適配器,而不是簡單地保存自己的一些輸入!

+0

+1 for boost :: iterator_adaptor。我也使用它,它對我很好。 – n1ckp 2009-11-23 15:04:45

0

更具體的what maxim1000 suggested版本:

#include <type_traits> 

template<typename Container, bool forward> 
class iterator_base 
{ 
public: 
    using value_type = 
     typename std::conditional<std::is_const<Container>::value, 
           const typename Container::value_type, 
           typename Container::value_type>::type; 

    iterator_base() { } 

    // For conversions from iterator to const_iterator. 
    template<typename U> 
    iterator_base(const iterator_base<U, forward>& other) 
    : c(other.c) 
    { 
     // .... 
    } 

    value_type& operator*() const 
    { 
     // ... 
    } 

    iterator_base& operator++() 
    { 
     if (forward) 
     { 
      // ... 
     } 
     else 
     { 
      // ... 
     } 
    } 

    iterator_base& operator++(int) 
    { 
     iterator_base copy(*this); 
     ++*this; 
     return copy; 
    } 

private: 
    Container* c = nullptr; 
    // ... 
}; 

using iterator = iterator_base<self_type, true>; 
using const_iterator = iterator_base<const self_type, true>; 

using reverse_iterator = iterator_base<self_type, false>; 
using const_reverse_iterator = iterator_base<const self_type, false>;