2014-11-18 6 views
0

for 문에 사용할 클래스 및 클래스에 대한 반복기 템플릿이 있습니다.대체 클래스에서 포인터를 사용하는 이유 기본 클래스에서 연산자 == 및 연산자! =

template<class T> 
class Itr2 { 
public: 
    Itr2() { } 
    ~Itr2() { } 

    typedef typename Itr2 type; 
    typedef typename T& reference; 

    virtual type& operator++()      { return *this; } 
    virtual T& operator*()      { return ((reference)*((type*)this)); } 
    virtual bool operator==(const type& o) const { return true; } 
    virtual bool operator!=(const type& o) const { return false; } 
}; 


template<class T> 
class I2 
{ 
public: 
    typedef I2<T> type; 
    typedef T  value; 
    typedef T& reference; 
    typedef typename Itr2<T> iterator; 

    virtual iterator& begin() { return *(new iterator()); } 
    virtual iterator& end() { return *(new iterator()); } 
}; 

다음으로 표준 표준 : 벡터 <>에 대한 클래스를 생성했습니다.

template<class T> 
class ItrSTD : public Itr2<T> { 
public: 
    typedef typename Itr2<T> base_type; 
    typedef typename ItrSTD<T> type; 
    typedef typename T& reference; 
    typedef typename std::vector<T>::iterator std_itr; 
protected: 
    std_itr itr_; 
public: 
    ItrSTD(const type& o)        { itr_ = o.itr_; } 
    ItrSTD(const std_itr& o)       { itr_ = o; } 

    virtual base_type& operator++()     { itr_++; return *this; } 

    virtual T&   operator*()      { return ((reference)(*this->itr_)); } 
    bool operator==(const base_type& o) const override { return (((const type&)o).itr_ == this->itr_); } 
    bool operator!=(const base_type& o) const override { return (((const type&)o).itr_ != this->itr_); } 
}; 



template<class T> 
class VSTD : public I2<T> { 
protected: 
    std::vector<T> arr_; 
public: 
    typedef typename ItrSTD<T> iterator; 

    VSTD(const VSTD& o) { arr_ = o.arr_; } 
    template<typename ...E> VSTD(E&&...e) : arr_({ std::forward<T>(e)... }) { } 

    iterator& begin() _NOEXCEPT override{ return (*new iterator(arr_.begin())); } 
    iterator& end() _NOEXCEPT override{ return (*new iterator(arr_.end())); } 

}; 

(int i : v)의 직접 구문을 사용하는 경우. 그것은 :(잘 작동하지만 내가 포인터 컴파일러 사용의 기본 클래스 연산자에서이 작업을 수행 할 때! = (연산자를 오버라이드 (override)하지! =) 및 코드가 작동하지 않습니다됩니다.

int v_i = 0; 
VSTD<int> vstd_a = { 1, 2, 3 }; 
I2<int> *i2 = &vstd_a; 

for (int j : *i2) //DOESN't work :(use operator!= from base class 
{ 
v_i += j; 
} 
for (int j : vstd_a) //work fine :) use operator!= from VSTD. 
{ 
v_i += j; 
} 

내가 코드를 단순화 경우 :() 나쁜 일 : : :

template<typename T> 
class I3 
{ 
public: 
    T i; 
    virtual bool operator==(const I3& o) const { return false; } 
}; 

template<typename T> 
class I3O : public I3<T> 
{ 
public: 
    virtual bool operator==(const I3& o) const override { return true; } 
}; 

I3O<int> i3_a, i3_b; I3<int> *i3_ap, *i3_bp; 

i3_ap = &i3_a; i3_bp = &i3_b; bool i3_c; 

i3_c = (i3_a == i3_b); 
i3_c = ((*i3_ap) == (*i3_bp)); 

두 결과

이 (true를 반환) 괜찮 만 (위해 (재정의 클래스에서 비교.

왜 이런 일이 템플릿 포인터 문에 사용할 수 있습니다 ? begin(), end() 함수는 잘 작동하며 연산자 만 다르게 작동합니다.

P. VS2013 컴파일러를 사용합니다.

+6

참조를 반환하는 함수에서'* new ... '를 실제로 반환하지 않습니다. 그렇습니까? 그것은 거의 보장 된 메모리 누수입니다. –

+0

클래스'Itr2'의 소멸자는 아마'가상', 아마도 순수한'가상'이어야합니다. –

답변

1

표준은 [stmt.]의 범위 기반 for 문에 대한 의미를 정의합니다.원거리]/1 형태

for (for-range-declaration : expression) statement 

범위 기반 for 문 용

범위-INIT 괄호에 둘러싸인 동등하게

(expression) 

및 범위 기반 for 양식의 경우

for (for-range-declaration : braced-init-list) statement 

범위-초기화가 보강-초기화 목록에 해당 될 수 있습니다. 각각의 경우에, 다양한 기반 for__range, __begin__end이 변수는 단지 설명을 위해 정의

{ 
    auto && __range = range-init; 
    for (auto __begin = begin-expr, 
      __end = end-expr; 
     __begin != __end; 
     ++__begin) { 
    for-range-declaration = *__begin; 
    statement 
    } 
} 

동등하고 _RangeT 표현식의 타입이고, 는-시작 EXPR 및 다음 최종 EXPR 결정된다

(1.1) - _RangeT가 배열 형식 인 경우 ...

(1.2) - _RangeT이 클래스 유형 인 경우, 클래스 멤버 액세스 룩업 (3.4.5)과 마찬가지로 _RangeT의 범위에서 정규화되지 않은 ID beginend을 조회하고 둘 중 하나 (또는 ​​둘 모두)가 하나 이상의 선언을 찾으면, begin-exprend-expr은 각각 __range.begin()__range.end()입니다.

(1.3) - 그렇지 않으면 ...

프로그램의 첫 번째 루프 :의 반환 형식 이후

{ 
    auto && __range = (*i2); 
    for (auto __begin = __range.begin(), 
      __end = __range.end(); 
     __begin != __end; 
     ++__begin) { 
    int j = *__begin; 
    v_i += j; 
    } 
} 

:

for (int j : *i2) //DOESN't work :(use operator!= from base class 
{ 
v_i += j; 
} 

가에 따라서 동일합니다 I2<int>::beginI2<int>::endItr2<int>&, __begin__endw 유형 Itr2<int>으로 추론되고 I2<int>::begin()I2<int>::end()의 반환 값에서 복사가 생성됩니다. 그 복사본 구성은 물론 반환 된 유형을 분할하고 기본 유형의 인스턴스로 끝납니다.

+0

포인터에서 값을 컴파일러에 알릴 수 있습니다 : auto && __range = (* i2); VSTD가 이고 I2가 아닌 입니까? 함수와 같은 함수를 만들고 싶습니다. (I * i); 모든 유형의 반복자를 계산합니다. 하지만 내가 할 수있는 일은 템플릿을 사용하는 것이다. function (T * i); –

4

코드의 세부 사항을 살펴 보지 않았지만 ... 이터레이터를 다형성으로 만들려고합니다. 그러나 표준 은 항상 값으로 전달하지만 값으로 전달하면 이 다형성을 지원하지 않습니다. 그것은 조각난다. 따라서 (I 가정)에서 :

for (int j : *i2) 

컴파일러는 그 유형 정적결정 반복기, 로컬 변수를 생성한다. 그리고 올바른 begin()을 호출하지만 결과를이 로컬 변수에 할당하여 슬라이스합니다. 이것은 상당히 비싼

Iterator(new DerivedIterator(...)); 

: 다음

class Iterator 
{ 
    Iterator* myImpl; 

    virtual Iterator* clone() const { abort(); } 
    virtual T& current() const { abort(); } 
    virtual bool isEqual(Iterator const* other) { abort(); } 
    virtual void next() { abort(); } 

protected: 
    Iterator() : myImpl(nullptr) {} 
public: 
    Iterator(Iterator* impl) : myImpl(impl) {} 
    Iterator(Iterator const& other) : myImpl(other.clone()) {} 
    virtual ~Iterator() { delete myImpl; } 

    T& operator*() const 
    { 
     return myImpl->current(); 
    } 
    bool operator==(Iterator const& other) const 
    { 
     return myImpl->isEqual(other.myImpl); 
    } 
    Iterator& operator++() 
    { 
     myImpl->next(); 
     return *this; 
    } 
    // ... 
}; 

class DerivedIterator : public Iterator 
{ 
    Iterator* clone() const override { return new DerivedIterator(*this); } 
    T& current() const override { ... } 
    bool isEqual(Iterator const* other) override { ... } 
    virtual void next() { ... } 
public: 
    DerivedIterator(...) ... 
}; 

같은 파생 beginend 반환 뭔가를 : 당신이 다형성 반복자가 필요한 경우

, 당신은 편지/봉투 관용구를 구현해야 하지만 실제로는 다형성을 제공하면서도 반복자가 필요로하는 값 의미를 가지고있는 유일한 방법은 입니다.

관련 문제