2013-04-05 1 views
3

에서 파생 된 개체의 컬렉션을 처리하는 가장 좋은 방법은 무엇입니까. 이제 'BaseA'를 확장하여 추가 기능을 추가하고자하므로 'BaseA'에서 'DerivedA'를 파생시킵니다. 'DerivedA'의 한 가지 특징은 'ItemA'항목 대신보다 정교한 'DerivedITemA'항목을 처리해야한다는 것입니다.내가 클래스 항목 'ItemA'의 컬렉션을 포함 'BaseA을'이 상상 파생 클래스

class DerivedA : public BaseA { 
    vector<DerivedItemA> x; 
    void m2(int i) { x[i].m2(); } 
}; 

즉 :

class BaseA { 
protected: 
    vector<ItemA> x; 
    void m1(int i) { x.m1(i); } 
}; 

class ItemA { 
protected: 
    void m1(int i) { ... } 
}; 

class DerivedItemA : public ItemA { 
    void m2(int i) { ... } 
}; 

지금은 이런 종류의 일을 처리하고 싶습니다 내 Derived 클래스에서 파생 된 항목을 처리하도록합니다. x의 위 정의는 BaseA에있는 것과 충돌하기 때문에 올바르지 않습니다. 그러나 나는 ItemA 요소를 다룰 때 x를 처리하는 BaseA의 모든 메소드를 재사용 할 수 있기를 원하고 DerivedAtA 데이터 유형의 추가 복잡성을 처리하기 위해 DerivedA에서 확장 된 메소드를 가짐

제안 사항이 있으십니까? 내 생각은 x (VectorOfItemA 예를 들어)에 대한 새로운 데이터 유형을 정의하고 VectorOfDerivedItemA에서 파생 된 선에 있습니다. 좀 더 간단하고 나은 솔루션이 있는지 궁금합니다.

덕분에

+1

"위의 x 정의는 BaseA에있는 정의와 충돌하므로 올바르지 않습니다." 아니, 파생 클래스의'x'는 기본 클래스의'x'를 숨 깁니다. 즉, 기본 클래스의 함수는 여전히 'BaseA :: x'에서 작동하지만 파생 클래스의 함수는 'DerivedA :: x'에서 작동합니다 (정규화되지 않은 -id를 사용). – dyp

+0

어떻게 요소를 벡터에 추가합니까? –

+0

의도 한 용도는 무엇입니까? 다형성 인'ItemA' 또는'DerivedItemA' 객체의 컬렉션 하나를 가지려면? 그렇다면 * 포인터 *를 개체 (이상적으로 스마트 포인터)에 저장해야하지만 원하는대로 정확히 표시되지는 않습니다. – WhozCraig

답변

0

나는 당신이 처리하기 위해 귀하의 벡터에서 포인터가 필요 믿습니다. 난 내가 인덱스 것으로 보인다 이후 M1과에 전달 m2 할 값을 조금 혼란 스러워요, 그러나 여기 내 생각 : 당신은, DerivedA에 항목을 추가 모두 X에 추가 할 때, 그리고

class BaseA { 
protected: 
    vector<ItemA*> x; 
    void m1(int i) { x[i]->m1(i); } 
}; 

class ItemA { 
protected: 
    void m1(int i) { ... } 
}; 

class DerivedItemA : public ItemA { 
    void m2(int i) { ... } 
}; 

class DerivedA : public BaseA { 
    vector<DerivedItemA*> y; //don't shadow the base class vector! 
    void m2(int i) { y[i]->m2(i); } 
}; 

와이. 그런 식으로 BaseA는 x에서 포인터로 할 수 있고 DerivedA는 y에서 포인터에 대해 할 수 있습니다.

편집 : 당신은 또한 그렇지 않으면 당신은 일을 DerivedA.y에 추가되지 않습니다 BaseA.x에 추가 얻을 수있는 항목을 추가하는 가상 방법을 제공해야합니다.

+0

BaseA의 메소드가 DerivedA의 메소드와 동일한 데이터 항목을 처리하도록하고 싶습니다. 따라서 두 개의 사본 x/y를 제거하려고합니다. 그리고 할 수 있는지보십시오.DerivedA의 생성자가 ItemA에서 DerivedItemA 요소 대신 Vector를 채우는 경우 DerivedA에서 x에 액세스 할 때 벡터 에 액세스하면 DerivedItemA의 메서드에 대한 액세스가 매 시간마다 DerivedItemA *로 다운 캐스트되어야합니다. ( – Miguel

+0

@metalhead 1. 누가 소유 할 것인가? DerivedA에 두 개의 벡터가 필요하지 않습니다. [예를 들어] (http://liveworkspace.org/code/44DC6x) –

0

당신은 호기심 반복 템플릿 패턴을 사용하려고 할 수 있습니다 - CRTP :

live demo

#include <iostream> 
#include <ostream> 
#include <vector> 

using namespace std; 

struct Item 
{ 
    void m1(int i) 
    { 
     cout << "m1(" << i << ")" << endl; 
    } 
}; 
struct DerivedItem : Item 
{ 
    void m2(int i) 
    { 
     cout << "m2(" << i << ")" << endl; 
    } 
}; 

template<typename Derived> 
struct IBase 
{ 
    void m1(int i) 
    { 
     for(auto &&z : static_cast<Derived*>(this)->x) 
     { 
      z.m1(i); 
     } 
    } 
}; 
template<typename Derived> 
struct IDerivedBase: IBase<Derived> 
{ 
    void m2(int i) 
    { 
     for(auto &&z : static_cast<Derived*>(this)->x) 
     { 
      z.m2(i); 
     } 
    } 
}; 

struct Base : IBase<Base> 
{ 
    vector<Item> x; 
}; 
struct DerivedBase : IDerivedBase<DerivedBase> 
{ 
    vector<DerivedItem> x; 
}; 

int main() 
{ 
    Base b; 
    b.x.resize(3); 
    DerivedBase d; 
    d.x.resize(1); 

    b.m1(11); 
    d.m1(22); 
    d.m2(33); 
} 

출력이입니다 :

m1(11) 
m1(11) 
m1(11) 
m1(22) 
m2(33) 

벡터 중 하나 BaseA에서 ItamA 모든 요소를 ​​포함합니다 인스턴스화 또는 DerivedA 인스턴스의 DerivedItemA의 모든 요소 혼합 할 필요가 없습니다.

  • 자료 < DerivedItemM1 방법
  • DerivedBase을 제공하는 유일한 벡터 < 항목>에만 벡터에게 있음 :

에는이 방법에서 어떤 조합이 없습니다 > 제공 m1m2 방법.


그러나, 실제 사용 패턴을 알지 못하고 - 당신이 필요 추측하기 어렵다. 어쩌면 두 독립형 벡터로 충분할 것입니다 :

vector<Item> x1; 
vector<DerivedItem> x2; 

그리고 단지 독립 실행 형 함수를 정의하십시오.

0

모든 수업을 소유하고 있습니까? 그렇다면 템플릿 기본 클래스로 리팩토링 할 수 있습니다. 당신은 또한 DerivedA을 받아 BaseA 소요 코드를 재사용하려는 경우

template <typename ITEM> 
class BaseT { 
protected: 
    vector<ITEM> x; 
    void m1(int i) { x[i].m1(); } 
}; 

typedef BaseT<ItemA> BaseA; 

class DerivedA: public BaseT<DerivedItemA> { 
    void m2(int i) { x[i].m2(); } 
}; 

, 당신은뿐만 아니라 템플릿 기능/클래스 수를 수정해야 할 수 있습니다.

그렇지 않으면 벡터에 대해 일종의 "다형성"기본 객체가 필요합니다. 이러한 접근법 중 하나는 Retrieve data from heterogeneous std::list (또는 내 후속 질문 : unique_ptr member, private copy constructor versus move constructor)에서 확인할 수 있습니다.


다형성 항목의 대안으로, 기반에 대한 인터페이스를 정의 할 수 있습니다. BaseA 요구됩니다 이제

class BaseI { 
protected: 
    virtual void m1(int) = 0; 
    //... other interfaces 
public: 
    virtual ~BaseI() {} 
    //... other public interfaces 
}; 

template <typename ITEM> 
class BaseT : public BaseI { 
protected: 
    vector<ITEM> x; 
    void m1(int i) { x[i].m1(); } 
    //...implement the other interfaces 
}; 

//... 

, 코드는 대신 BaseI을 위해 리팩토링한다. 이 새로운 코드는 DerivedA을 받아 들일 수 있습니다.

+0

예 모든 클래스를 소유하고 있습니다. 템플릿을 만들기에는 너무 큽니다. 또한 헤더 파일의 모든 기능을 노출시키지 않고 라이브러리의 일부로 만들려고합니다. – Miguel

+1

템플릿을 사용할 수는 있지만 템플릿의 명시적인 인스턴스화를 통해 구현 세부 사항을 숨길 수 있습니다. 도서관 비 - 헤더 소스 파일 내에서 템플릿. 그러나, 당신은 내가 다른 아이디어에 대한 내 대답을 추가 한 두 개의 링크를 수행 할 수 있습니다. – jxh

+0

당신이 정교 할 수 있니? – Miguel