2011-02-17 4 views
2
class IFeature 
{ 
public: 
    virtual std::string string() = 0; 
}; 

class Feature2D 
{ 
public: 
    virtual std::string string() { .... } 
}; 

class Feature3D 
{ 
public: 
    virtual std::string string() { .... } 
}; 

void print(std::vector<IFeature*> & v) 
{ 
    for (size_t i=0; i<v.size(); i++) 
    std::cout << v[i]->string() << std::endl; 
} 

void main() 
{ 
    std::vector<Feature2D*> v2d; 
    // push... 
    print(v2d); // compile error 

    std::vector<Feature3D*> v3d; 
    // push... 
    print(v3d); // compile error 
} 

이 인쇄 기능을 어떻게 얻을 수 있습니까? (아마도 std :: vector와 다른 다른 데이터 구조를 사용합니다)C++에서 상속 된 객체의 벡터

감사합니다.

+1

벡터를 const 참조에 의해'print' 할 수 있습니다. 또한 상속 문이'FeatureXD' 클래스 선언에 없습니다. –

+0

@Stefan - 질문에 게시 된 코드를 수정하지 마십시오. 모든 오류는 OP가보고있는 문제의 ** 원인 ** 일 수 있습니다. – ChrisF

+0

예, 물론, 제가 생각한 것은 무엇입니까 :) –

답변

2

템플릿을 사용하십시오. 그냥 벡터 iFeature에 * -vectors을

class IFeature 
{ 
public: 
    virtual std::string string() = 0; 
    virtual void print(std::ostream & Dest) const = 0; 
}; 

void print(std::vector<IFeature *> const & v) { 
    for (size_t i=0; i<v.size(); i++) { 
    v[i]->print(cout); 
    cout << endl; 
    } 
} 

가 선택적으로 운영자 < <

inline std::ostream & operator<<(std::ostream & Dest, IFeature const & v) { 
    v.print(Dest); 
    return Dest; 

void print(std::vector<IFeature *> const & v) { 
    for (size_t i=0; i<v.size(); i++) 
    std::cout << *(v[i]) << std::endl; 
} 
+0

대단히 고마워요! "const"가 무엇입니까? – yelo3

+0

인쇄가 수정되지 않음을 나타냅니다. – Erik

2

와 결합 :

template<typename T> void print(std::vector<T *> const & v) { 
    for (size_t i=0; i<v.size(); i++) 
    std::cout << v[i]->string() << std::endl; 
} 

또는 가상 프린트 멤버 함수를 사용합니다. 상속 된 클래스에 대한 포인터를 잘 저장할 수 있습니다.

std::vector<IFeature*> v2d; 
v2d.push_back(new Feature2D()); 
print(v2d); 

템플릿을 사용할 필요가 없습니다. 수퍼 클래스에 대한 포인터는 일반적인 가상 함수에 액세스해야 할 때 사용할 수있는 방법입니다. 이 방법을 사용하면 같은 벡터 내에서 다른 서브 클래스를 혼합 할 수 있습니다 : 물론

std::vector<IFeature*> vMixed; 
vMixed.push_back(new Feature2D()); 
vMixed.push_back(new Feature3D()); 
print(vMixed); 

, 당신은 또한 상속 된 클래스에 대한 포인터를 필요로하는 경우, 상황이 조금 더 까다로운. 하나의 옵션은 별도로 다른 위치에 저장하는 것입니다. 다운 캐스트 할 수도 있지만 일반적으로 추천할만한 것은 아닙니다.

+0

벡터를 통해 상속 된 클래스에 액세스해야하는 경우에는 작동하지 않습니다. (당신은 추한 다운 캐스트가 필요합니다.) – Thomas

+0

그래, 그것을 고려 편집. –

1

당신은 템플릿에 print 자체를 만들 수 있습니다

template<typename T> 
void print(T const &v) 
{ 
    for (size_t i=0; i<v.size(); i++) 
    std::cout << v[i]->string() << std::endl; 
} 

더 나은 아직, 반복자를 사용, 그것은뿐만 아니라 대부분의 다른 표준 컨테이너에서 작동합니다 :

template<typename T> 
void print(T const &v) 
{ 
    for (T::const_iterator i = v.begin(); i != v.end(); ++i) 
    std::cout << (*i)->string() << std::endl; 
} 

더 나은 (감사 Pedro), 반복기 자체를 전달하십시오.

template<typename Iter> 
void print(Iter begin, Iter end) { 
    for (Iter i = begin; i != end; ++i) 
    std::cout << (*i)->string() << std::endl; 
} 
+1

나는 한 걸음 더 나아가서 T에 대한 const 참조보다는 반복자에 대해 작업 할 것을 제안했다. 그래서 : template void print (InputIterator begin, InputIterator end) {...} –

+0

좋은 지적, 고마워. 편집 됨. – Thomas

0

원하는 것을 찾으십시오. 여기에 대한 인터페이스 공분산입니다, (내가 아는 한) C++ 클래스에서는 불가능합니다. 템플리트 함수 (IFeature *를 T *로 대체)도 인쇄해야합니다.

1

모든 벡터가 동일한 이진 코드를 공유하기 때문에 완전하게하기 위해 벡터를 다시 해석 할 수 있다고 덧붙입니다.

print(reinterpret_cast<std::vector<IFeature*>&>(v2d)); 

C++ 템플릿 매개 변수에 대한 공분산을 가지고 있지 않지만, 당신이 후드 무엇을 알고 부분적 경우 당신은 그것을 시뮬레이션 할 수 있습니다. reinterpret_cast가 contavvariance로 vector<T*>&vector<const T*>&으로 변환하는 데 유용하다는 것을 알았습니다.

허용됩니다. 매우 불편합니다.

관련 문제