2014-03-12 4 views
2

현재 begin()end()을 포함한 몇 가지 가상 메소드를 제공하는 인터페이스 (다음 예에서는 Base)를 설계 중입니다. 이 두 메소드는 클래스와 같은 다른 콜렉션과 같이 대응하는 반복자를 리턴한다. 파생 클래스는 이러한 메서드를 구현하고 iterator의 특정 구현을 반환해야합니다.기본 클래스의 기본 이터레이터 설계

다음은 (단순화 된) 예제는 boost::transform_iterator을 사용하여 개인 내부 정수 목록을 변환하는 파생 클래스를 보여줍니다. 이 구현은 실제로 반복되는 "물건"이 다른 것일 수 있다는 반복자의 예일뿐입니다.

예제가 작동하지만 문제가 하나 있습니다. main()의 오브젝트 유형은 사용 된 반복자가 TransformIterator 유형이라는 사실을 숨기지 않습니다. 기본 클래스는 모든 플러그인이 공유 라이브러리 인 일종의 플러그인 아키텍처에서 사용됩니다. 플러그인은 사용되는 반복자의 유형을 알지 않아야하며 추상 인터페이스에만 의존해야합니다. 이것을 할 수있는 방법이 있습니까?

#include <boost/iterator/transform_iterator.hpp> 

#include <iostream> 
#include <string> 
#include <vector> 

template<class Iterator> 
class Base 
{ 
public: 
    virtual Iterator begin() = 0; 
    virtual Iterator end() = 0; 
}; 

struct toString 
{ 
    std::string operator()(int number) const 
    { 
     return std::to_string(number); 
    } 
}; 

typedef boost::transform_iterator<toString, std::vector<int>::iterator> TransformIterator; 

class Derived : public Base<TransformIterator> 
{ 
public: 
    Derived() : ints{132, 3, 6451, 12, 5} {} 

    TransformIterator begin() 
    { 
     return boost::make_transform_iterator(ints.begin(), toString()); 
    } 

    TransformIterator end() 
    { 
     return boost::make_transform_iterator(ints.end(), toString()); 
    } 

private: 
    std::vector<int> ints; 
}; 

int main() 
{ 
    Base<TransformIterator>* obj = new Derived(); 
    for(const auto& value : *obj) 
    { 
     std::cout << value.size() << std::endl; 
    } 
    return 0; 
} 

조금 더 배경 :이 특정 예는 구성 파일을 읽는 인터페이스를 기반으로합니다. 현재 YAML 파일에 대한 구현 만 제공 할 계획이지만 XML 또는 이전 학교 INI와 같은 다른 형식도 가능합니다. 따라서 공통 인터페이스.

답변

1

고전적인 C++ 이터레이터에는 없습니다. 다형성을 목적으로하지 않습니다.

당신이 할 수있는 일은 반복자에 대한 추상 기본 클래스를 정의한 다음 각 반복기 유형에 대한 (템플릿으로 묶인) 래퍼로 구현하는 것입니다. 추상 기본 클래스는 단순히 모든 필수 연산자를 순수 가상으로 정의합니다. 단점은 반복기의 모든 연산에서 가상 함수 호출이 필요하다는 것입니다. 사용에 따라 문제가 될 수도 있고 아닐 수도 있습니다 (일반적으로 매우 큰 컬렉션을 반복 할 때 사용하지 않는 한).

예 :

template <typename T> 
class InputIterator<T> 
{ 
    public: 
    virtual T operator*() const = 0; 

    // Other operators go here 
}; 

template <typename TIterator> 
class ConcreteInputIterator final 
: public InputIterator<typename std::iterator_traits<TIterator>::value_type> 
{ 
    public: 
    ConcreteInputIterator(TIterator iterator) : m_iterator(iterator) {} 

    public: 
    virtual T operator*() const override 
    { 
     return *m_iterator; 
    }; 

    private: 
    TIterator m_iterator; 
}; 
+0

아 이제 해결책을 찾지 못했습니다. 이 특별한 경우에는 가상 함수 호출이 문제가되어서는 안됩니다. 구성은 시작시 한 번 읽습니다. – tea2code

+1

참고 : STL 알고리즘과 함께 사용하려면 추상 반복자에 대해 std :: iterator_traits를 전문화하거나 이미 적절한 전문화가 적용된 std :: iterator에서 파생 시키길 원할 것입니다. – heinrichj

2

나는 최근에 직장에서 내 프로젝트 중 하나에서 매우 비슷한했다. 내가 한 방식은 추상 iterator 인터페이스와 iterator가 해당 인터페이스에 액세스하는 클래스를 소개하는 것입니다. 다음은 간단한 버전입니다.

template <class ValueType> 
struct AbstractIterator 
{ 
    virtual ValueType& dereference() const = 0; 
    virtual void increment() = 0; 
    // and so on... 
}; 


template <class ValueType> 
struct ClientIterator : public std::iterator<whatever> 
{ 
    std::unique_ptr<AbstractIterator<ValueType>> it; 

    ClientIterator(std::unique_ptr<AbstractIterator<ValueType>> it) : it(std::move(it)) {} 

    ValueType& operator* const() { return it->dereference(); } 
    ClientIterator& operator++() { it>increment(); return *this; } 

    // and so on... 
}; 

struct Base 
{ 
    typedef ClientIterator<std::string> Iterator; 
    virtual Iterator begin() = 0; 
    virtual Iterator end() = 0; 
} 


struct Derived : Base 
{ 
    struct ServerIterator : AbstractIterator<std::string> 
    { 
    boost::transform_iterator<toString, std::vector<int>::iterator> it; 

    virtual std::string& dereference() const override { return *it; } 
    virtual void increment() override { ++it; } 
    } 

    virtual Iterator begin() override { return Iterator({new ServerIterator(something)}); } 
    virtual Iterator end() override { return Iterator({new ServerIterator(anotherThing)}); } 
}; 
+0

감사합니다. 나중에 예를 확인할 것입니다. – tea2code

+0

'virtual' +'override'는 약간 장황 해 보이는데 왜'override' 만 아니겠습니까? – TemplateRex

+0

@TemplateRex 아무 이유없이, 항상 오버라이드에'가상'를 두는 습관이 있습니다. – Angew