2016-09-20 144 views
-1

如何編寫基類和迭代器的幾個派生類?迭代器繼承和繼承*這個

迭代器是否必須返回自己(* this)?

到目前爲止,我使用typename Xstatic_cast<X&>(*this)來允許派生類繼承一個從基類返回自身的函數。

This看起來很醜。有沒有更好的辦法?

簡化代碼:

#include <iterator> 
#include <iostream> 
template <typename T, typename X> 
class BaseIterator : public std::iterator<std::input_iterator_tag, T> { 
    //Not intended to be used directly. 
    private: 
     T* p; 
    protected: 
     virtual void increment(void)=0; 
     virtual T* stride_index(int index)=0; 
    public: 
     virtual ~BaseIterator(){} //virtual destructor. 
     X operator++(int) { //takes a dummy int argument 
      X tmp(static_cast<X&>(*this)); 
      increment(); 
      return tmp; 
     } 
     bool operator==(const X & rhs) { return p==rhs.p; } 
} ; 
template <typename T> 
class ContiguousIterator : public BaseIterator<T, ContiguousIterator<T> > { 
    private: 
     T* p; 
    protected: 
     inline void increment(void) {++p;} 
     inline T* stride_index(int index){return p + index;} 
    public: 
     virtual ~ContiguousIterator(){} //destructor. 
     ContiguousIterator(T* x) :p(x) {} 
     ContiguousIterator(const ContiguousIterator<T> & mit) : p(mit.p) {} 
} ; 

int main(void){ 
    int i[]={0,1,2,3,4,5}; 
    ContiguousIterator<int> itbegin(i); 
    ContiguousIterator<int> it(i); 
    it++; 
    std::cout << "result: " << (it == itbegin) << std::endl; 
} 

替代方案是關於使用繼承來寫更少的代碼給忘了。只需複製並粘貼返回*this的函數到派生類。

,替代似乎越來越接受我......

+1

另外'ContiguousIterator'有兩個不相關的公共'T * p'成員,就是這樣混亂。 –

+0

我不知道crtp。在這種情況下,crtp會有幫助嗎? – rxu

+0

簡單修復:將T * p改爲私有。無法將其更改爲受保護的。不知何故。我曾嘗試過。 – rxu

回答

1

一般來說,virtual是像迭代器這應該是輕量級的很多開銷。通常的方式是CRTP。這是一個有點棘手,但看起來是這樣的:

template <typename T, typename X> 
class BaseIterator : public std::iterator<std::input_iterator_tag, T> { 
    protected: 
     T* p; 
     X* self() {return static_cast<X*>(this);} 
     const X* self() const {return static_cast<const X*>(this);} 
     BaseIterator(T* x) :p(x) {} 
    public: 
     X operator++(int) { //takes a dummy int argument 
      X tmp(*self()); 
      self()->increment(); 
      return tmp; 
     } 
     bool operator==(const X & rhs) const { return p==rhs.p; } 
} ; 

基地通常需要派生類型,再加上任何需要的功能簽名作爲模板參數。然後添加兩個self()函數,它們會給出派生類型,這意味着您實際上不需要virtual。一切都由編譯器內聯。 (注意:我也給了它一個理智的構造,並取得operator==const

template <typename T> 
class ContiguousIterator : public BaseIterator<T, ContiguousIterator<T> > { 
    public: 
     typedef BaseIterator<T, ContiguousIterator<T> > parent; 
     void increment(void) {++(this->p);} 
     T* stride_index(int index) const {return this->p + index;} 
    public: 
     virtual ~ContiguousIterator(){} //destructor. 
     ContiguousIterator(T* x) :parent(x) {} 
     ContiguousIterator(const ContiguousIterator<T> & mit) : parent(mit.p) {} 
} ; 

然後派生類型繼承簡單正常,除了你必須使用this->訪問成員,因爲父是一個模板見它在這裏工作:http://coliru.stacked-crooked.com/a/81182d994c7edea7

這將產生一個高效的迭代器,在沒有開銷的,我相信這種技術被用來比較巨資加速迭代器庫:http://www.boost.org/doc/libs/1_59_0/libs/iterator/doc/#new-style-iterators

+0

我的天。我不知道虛擬會給迭代器帶來很大的開銷。 http://programmers.stackexchange.com/questions/191637/in-c-why-and-how-are-virtual-functions-slower非常感謝你的回答。 – rxu

+0

@rxu:鑑於您不使用該基礎,虛擬可能不會爲您的案例添加任何開銷。但這保證不會。 –

+0

爲基類聲明一個虛擬析構函數是個好主意嗎?這會造成任何開銷嗎? – rxu