2012-09-03 11 views
3

저는 C++에 좀 새로운 것 같습니다. 2 클래스가 상속하는 추상 클래스 (순수 가상)가 있습니다. 각각의 파생 클래스는 다른 STL 컨테이너 (배열 대 맵)에서만 유사한 데이터를 보유합니다. 예를 들어 STL 요소의 추가를 수행하기 위해 기본 클래스의 연산자를 오버로드하고 있습니다. 어떤 유형인지에 관계없이 STL의 요소를 반복 할 수 있기를 원합니다.다형성의 일반 STL 반복자

일반 이터레이터에서 며칠 동안 검색했지만 그와 같은 항목은 있지만 찾을 수 없습니다.

아무 것도 할 수 없어 너무 공유 할 코드가 없습니다. 아마도 기본 클래스에 STL 컨테이너를 나타내는 템플릿 변수를 보유한 다음 연산자에서 iterator를 가져올 수 있지만 다시는 확실하지 않은 것으로 생각했습니다.

protected: 
    template<class T> 
    T gStlContainer; 

다음

gStlContainer::iterator<double> it; 

분명히 작동하지 않았다 접근.

제안 사항? 감사합니다.

편집 : 예제를 사용하여 더 잘 설명해 보도록 편집 중입니다. 기본 (추상) 클래스에서 + 연산자를 오버로드하고 있는데, STL 컨테이너의 각 요소를 반복하고 다른 요소 (예 : )에 추가한다고 가정합니다. STL로이 배열이 있다고 가정 해 보겠습니다.

arr = [0,1,2,3] // Say it's stored in Derived2 class 
arr = [4,5,6,7] // Say it's stored in Derived3 class 

이러한 배열은 각각 파생 클래스 중 하나에 저장됩니다. 내가

Derived1 = Derived2 + Derived3; 

을하고있을 때 다음 Derived1에 저장할 것

arr = [4,6,8,10] 

는 이제 좀 더 분명 바랍니다. 문제는 그것이 항상 배열이 아니며, 예를 들어 배열과지도를 결합 할 수 있다는 것입니다. 그래서 일반 반복기 또는 일부 솔루션이 필요합니다.

감사합니다.

+0

기본 클래스의 인터페이스는 무엇입니까? (원하는 모양의 제한된 버전 표시). 나는 또한 사용해야합니까 표준의 버전을 유의 ... 기본 클래스의 인터페이스를 정의하고 템플릿 인수로 컨테이너의 형식을 취하는 하나의 템플릿 파생 된 유형을 구현 보는 것 (C++ 03/C++ 11)과 같이 라이브러리를 사용할 수 있는지 여부를'부스트 : function' 또는'표준 : function'합니다.알고리즘의 단일 구현을 제공 할 필요가없고 각 파생 된 유형이 반복을 수행해야하는 경우 다시 훨씬 더 간단 할 수 있습니다. –

답변

1

C++에는 일반 이터레이터가 없지만 모든 유형의 이터레이터에서 작동하도록 작성 될 수있는 템플릿 함수가 있습니다. 컨테이너의 모든 요소를 ​​추가하려면 이미 알고리즘이 있습니다. std::accumulate에 대해 읽어보십시오.

+0

답장을 보내 주셔서 감사합니다. 죄송합니다. 어떻게 도와 주는지 이해하지 못하셨습니까? 또한, 제 질문을 편집하여 더 나은 설명을했습니다. –

1

잘못된 관점에서 문제를보고 있습니다. 니가 할 수는있어, 근데 너 왜? 기본 클래스는 다르게 동작해야하는 경우 메서드를 구현하면 안되지만 논리를 파생 클래스에 위임해야합니다.

class Base 
{ 
public: 
    virtual ~Base() {} 
    virtual void iterate() = 0; 
}; 

class Derived : Base 
{ 
public: 
    virtual void iterate() { /*iterate through vector or map or whatever*/ } 
}; 
+0

답장을 보내 주셔서 감사합니다. 반복 할 함수가 연산자 오버로딩이며 각 사례에 대해 과부하하고 싶지 않습니다. 즉 배열을 배열에 추가, 배열에 맵 추가 등) 더 구체적인 예를 포함하도록 질문을 편집했습니다 –

+0

@Lablabla 논리가 잘못되었습니다. 어느 요소가'map [1]'리턴해야합니까? 지도가 순차적이지 않습니다 ... –

+0

map [i] 여기서 int-> double 매핑을 array [i]에 추가해야하고 map [i]이없는 경우 0으로 처리합니다. 그러나 그것은 조금 나중에있다. 운동 설명은 우리가 STL 컨테이너를 돌 보지 않고 이런 식으로 구현해야한다고 말합니다. 지도가 구체적으로 언급되어 있습니다. –

0

평범한 대답은 적어도 STL의 반복기에서는 불가능합니다.

반복자는 일반적으로 템플릿으로 작성되며 컴파일러는 각 템플릿 전문화에 대해이라는 새 유형을 만듭니다. vector :: iterator는 VectorFloatIterator와 같고 Map :: iterator는 MapFloatIterator로 생각할 수 있습니다.

이들은 상속을 통해서조차도 유사한 인터페이스를 가지고 있으며, 물론 C++은 오리가 입력되지 않은 비 관련 유형입니다. 두 가지 유형이 완전히 무관 한 경우 MapFloatIterator를 예상하는 함수에 VectorFloatIterator를 전달할 수 없습니다.

표준 알고리즘을 사용하는 경우에도 적용됩니다. 예를 들어 for_each 알고리즘은 템플릿 처리되므로 컴파일러는 서로 사용할 수없는 for_each_vector_float_iterator 및 for_each_map_float_iterator 함수를 만듭니다.

컴파일 할 때에서 생성되는 유형이 이라고 생각하면 도움이됩니다. 함수에 다른 유형을 전달하는 작업은 런타임에 너무 늦어서 발생합니다. 컴파일시에 C++의 템플릿의 "genericization"(예, 나는 그 단어를 만들었습니다) 기능 만 사용할 수 있습니다.

@Luchian Grigore는이 문제에 대해 가장 잘 알려진 답변을 가지고 있습니다. 추가 문에 나타날 수있는 다양한 유형을 처리하기 위해 operator+을 전문화하십시오. 고통입니까? 그래, 조금.

말했다되고 그건

, boost::any는 사용 사례에 대한 찾고있는 것입니다 - 그들은 다양한 유형을 처리하는 템플릿을 사용하여 하지에 의해 어떤 유형을 처리 STL과 같은 컨테이너입니다.

1

동적 다형성은 객체에 대해 합리적인 동작을하지만 알고리즘에 실제로 잘못 작동합니다. 알고리즘의 경우 정적 다형성을 사용하는 것이 훨씬 낫습니다. 그들 사이에 operator+()을 지원하는 컨테이너 시스템을 원한다고 생각한다면, 어떻게 든 네임 스페이스를 참조하고이 네임 스페이스에 적절한 operator+()을 정의하십시오. 예를 들어 std::vector<T, A>을 사용하고 할당 자 A을 네임 스페이스의 어떤 것에서 상속 한 연산자를 사용할 수 있습니다. 아래는이 방법의 예입니다.

아이디어는 기본적으로 적합한 연산자를 구현하는 네임 스페이스를 갖는 것입니다. 예를 들어 addableoperator+()을 구현하고 printableoperator<<()을 구현합니다. 이 네임 스페이스 중 어느 것도 유형이 어떻게 든 그들을 참조하지 않는 한 바라본다. 이 네임 스페이스의 형식에서 상속하거나 이러한 형식 중 하나를 상속하는 형식의 템플릿 인수를 사용합니다. 이 모양 메커니즘은 인수 종속 검색보다입니다. 따라서이 두 네임 스페이스는 모두 struct tag {};을 상속받을 때 비용이 들지 않습니다. 다만 이러한 유형 모두에서 파생 할당 자 클래스 템플릿을 생성 아래

다음 네임 스페이스에 어떻게 든 코드를 참조 컨테이너를 잡아합니다. 이 할당은 용이하게 대응하는 용기를 만드는 타입 별명을 작성하고 std::vector<T, A> std::list<T, A> 함께 사용된다. 모든 것을 잘 나타내려면 main() 그냥 연산자의 사용을 보여줍니다.

아래 코드는 표기가 조금 짧게 여러 곳에서 C++ 2011을 활용합니다. 이 원리는 C++ 2003에서도 작동합니다. 주로 타입 별칭과 초기화리스트의 사용은 작동하지 않습니다.

#include <algorithm> 
#include <functional> 
#include <iostream> 
#include <iterator> 
#include <list> 
#include <vector> 

namespace addable 
{ 
    struct tag {}; 

    template <typename T0, typename T1> 
    T0 operator+ (T0 const& c0, T1 const& c1) 
    { 
     T0 rc; 
     std::transform(c0.begin(), c0.end(), 
         c1.begin(), 
         std::back_inserter(rc), 
         std::plus<typename T0::value_type>()); 
     return rc; 
    } 
} 

namespace printable 
{ 
    struct tag {}; 
    template <typename T, typename = typename T::value_type> 
    std::ostream& 
    operator<< (std::ostream& out, T const& value) 
    { 
     out << "["; 
     if (!value.empty()) { 
      std::copy(value.begin(), value.end() - 1, 
         std::ostream_iterator<typename T::value_type>(out, ", ")); 
      out << value.back(); 
     } 
     return out << "]"; 
    } 
} 

template <typename T> 
struct my_allocator 
    : addable::tag 
    , printable::tag 
    , std::allocator<T> 
{ 
}; 

template <typename T> 
using my_vector = std::vector<T, my_allocator<T>>; 
template <typename T> 
using my_list = std::vector<T, my_allocator<T>>; 

int main() 
{ 
    my_vector<int> v({ 1, 2, 3, 4 }); 
    my_list<int> l({ 2, 3, 4, 5 }); 
    my_vector<int> rc = v + l; 

    std::cout << v << " + " << l << " = " << (v + l) << "\n"; 
}