2013-02-04 27 views
0

例如應將下列類別分成兩部分:re C++範圍迭代器:只有一個類是不好的?

class Range { 
public: 
    Range(int end); 

    Range begin(); 
    Range end(); 

    // Second class would contain these methods. 
    bool operator!=(const Range& range); 
    int operator*(); 
    void operator++(); 
}; 

// Print 012 
// Almost as pretty as Python :D 
for (int i : Range(3)) { 
    std::cout << i; 
} 

PS:在標準庫中是否有這樣的類?

更新:

這裏的替代設計會是什麼樣子:

class Range; 

class RangeIterator { 
public: 
    bool operator!=(const RangeIterator& range_iterator); 
    int operator*(); 
    void operator++(); 

private: 
    RangeIterator(const Range& range); 
}; 

class Range { 
public: 
    Range(int end); 

    RangeIterator begin(); 
    RangeIterator end(); 

    friend class RangeIterator; 
}; 
+1

不完全是,雖然有'std :: iota'。 – chris

+4

'boost :: irange'。 – Pubby

+0

我不知道有多少次我可以忘記存在。這非常有用。不久之後,至少範圍內正在向標準庫發展。 – chris

回答

2

就我個人而言,我將它分開 - C++中的類型安全點是,當您將範圍傳遞給本應採用迭代器的函數時,編譯器會告訴您,反之亦然。如果同一個班級同時扮演這兩個角色,那麼你會失去這個角色,如果myrangemyrange.begin()具有相同的類型,那麼這是一個現實的錯誤。也就是說,既然你也喜歡Python,你可能不會認爲這是一個大問題,你習慣於存在__iter__返回self的對象。從C++ POV中我會說這可能看起來有點不尋常/棘手/聰明。

但這並不意味着RangeIterator必須在您的界面中公開定義。您可以使用typedef Range::iterator_type,由私有嵌套類或名稱空間中定義的類支持。無論哪種方式,有人可以檢查頭文件中的類定義,但除了「可以通過名稱Range::iterator_type引用它」以外,您不會記錄任何內容,以下是您可以使用的方法。

說起來,RangeRangeIterator目前都滿足迭代器的要求。如果您決定要將Iterator作爲迭代器,那麼您需要專門編寫std::iterator_traits,添加一些typedefs或從std::iterator派生(常用選項)。因此,無論您採用哪種方式,都需要包含更多樣板。這可能會影響你的決定。首先要寫的東西越多,定義一個額外類的成本越低。

這裏的RangeIterator變成一個iterator:

class RangeIterator : public std::iterator<std::input_iterator_tag, int> { 
public: 
    bool operator!=(const RangeIterator& range_iterator) const; 
    bool operator==(const RangeIterator& range_iterator) const; 
    int operator*() const; 
    RangeIterator &operator++(); 
    RangeIterator operator++(int); 

private: 
    RangeIterator(const Range& range); 
}; 
+0

添加這些基類是做什麼的?我認爲for循環不需要添加基類就可以工作。 – allyourcode

+0

@allyourcode:'std :: iterator'可以幫助類滿足標準中所謂的「迭代器要求」。滿足要求的類型通常稱爲「迭代器」。你是正確的,基於範圍的for循環不需要一個迭代器,但是已經到了一半的地方,讓你的類成爲一個迭代器是一個不錯的主意(特別是對於它中有'Iterator'的版本名稱)。那麼你可以使用它與標準算法以及基於範圍的。迭代器只是「C++方式」,就是這樣。 –

0

它是否應該被分成兩個班取決於該軟件將被使用的上下文很多。例如,如果軟件的其餘部分與此類型的代碼無關,也許這是合理的,並且降低了複雜性,以保持一致。另一方面,如果您正在努力擁有某種通用實用程序,那麼可維護性(或者可以說,爲了簡單起見)更好地分解事情。

我覺得你應該考慮可維護性和可讀性,而不是像這樣對代碼片段有一個硬性規則。從長遠來看,您的設計選擇會讓事情更容易維護嗎?它會降低項目的複雜程度嗎?

這是構建軟件的一件很酷的事情!

+0

我發現它的一個煩人的事情,因爲我總是首先想到困難的方式;) – chris

+0

我想這可能是它自己的設計目標;-) – Kirby

+0

我的問題基本上歸結爲到「哪種方式更容易維護?」。這個問題的一個重要方面是「人們期望什麼?」。如果人們(幾乎)總是有兩個班級,我想知道這一點。 – allyourcode

0

我會簡單的堅持使用第二種方法,它有一些好處:

  1. 您可能要遍歷以不同的方式Range,取決於你想要完成什麼 。但是,您可能不希望使用不同遍歷操作的接口膨脹,即使您可以預見到您將需要的操作也不例外。

  2. Range對象分離的穿透機制讓我們 定義不同的遍歷策略迭代器不 在Range接口枚舉它們。例如, FilteringRangeIterator可能僅提供對那些滿足特定過濾約束的元素 的訪問。

  3. 您可能想要提供多態性到Range,然後您可以 推廣迭代器概念以支持多態迭代。