2016-09-20 2 views
-1

반복기의 기본 클래스 및 여러 파생 클래스를 작성하는 방법은 무엇입니까?Iterator 상속 및 상속 * this

반복자가 자신을 반환해야합니까 (* this)?

지금까지는 파생 클래스가 기본 클래스에서 자신을 반환하는 함수를 상속 할 수 있도록 typename Xstatic_cast<X&>(*this)을 사용했습니다.

This ugly. 더 좋은 방법이 있습니까?

간체 코드 :

#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 : 기본을 사용하지 않는다면 virtual은 아마도 당신의 경우에 오버 헤드를 추가하지 않을 것입니다. 하지만이 보장하지 않습니다. –

+0

기본 클래스의 가상 소멸자를 선언하는 것이 좋은 생각입니까? 이로 인해 오버 헤드가 발생합니까? – rxu