2012-12-20 6 views
2

일부 제약 조건에 따라 유형이 다른 멤버가있을 때 어떻게 다형성을 디자인합니까? 다형성 디자인, 추상 클래스로 템플릿

내가이이 말 :

나는 다른 매개 변수에 따라 새로운 파생 된 개체, 즉 생성 할 수 있도록하려면
template<typename T> 
class Base 
{ 
public: 
    Base() = default; 
    virtual ~Base() = default; 
    T member; 
}; 

class DerivedA : public Base<int> 
{ 
public: 
    DerivedA() {member = 5;} 
}; 

class DerivedB : public Base<float> 
{ 
public: 
    DerivedB() = default; 
}; 

: 분명히

Base *b; 
if (something) 
    b = new DerivedA(); 
else 
    b = new DerivedB(); 

내가 있기 때문에이 작업을 수행 할 수 b 선언에 대한 템플릿 매개 변수를 제공해야합니다.

이 나쁜 디자인인가요? 어떻게 처리합니까?

난 작은 래퍼 작성할 수

class Wrapper() {}; 

template<typename T> 
class Base : public Wrapper 
{ 
// ... 
}; 

Wrapper a, b; 
a = new DerivedA; 
b = new DerivedB; 

을하지만 내가 Base 또는 Derived에 선언 member 또는 다른 방법에 직접 액세스 할 수 없습니다. 나는 캐스팅해야한다 : reinterpret_cast<DerivedA*>(a)->member, 다형성을 쓸모 없게 만든다.

감사합니다.

+0

디자인에 문제가 있습니다 ... 래퍼 인터페이스는 정상 상태 여야하지만 작동하려면 문제를 되돌려 야합니다. – Synxis

+0

이것은 내 마음에 온다 http://en.wikipedia.org/wiki/Policy-based_design – user1849534

+0

세 번째 수준의 기초? –

답변

0

래퍼 디자인은 원하는 것을 정확하게 선택해야합니다. 문제는 C++가 정적으로 형식화되어 있으므로 형식을 지정하지 않고 멤버를 선언 할 수 없다는 것입니다. 이것을 피하는 일반적인 방법은 원하는 모든 기능을 지원하는 기본 클래스를 디자인하고, 파생 된 클래스에서 특정 동작을 구현하는 것입니다.

아마 문제는 클래스가 필요한 모든 기능을 지원하지 않는다는 것입니다. 멤버를 직접 사용하지 않고 가상 메소드에 사용법을 래핑하십시오. 파생 클래스에서 이러한 메서드를 다시 구현하십시오.

여전히 옵션이 아니라면 회원 추출 방법을 고려하십시오. 아마도 적절한 변환을하는 가상 getter 및 setter 일 수 있습니다.

마지막 수단으로 boost :: variant, boost :: any를 고려하십시오. 그러나 실제로는 랩퍼와 유사한 기술을 사용하여 구현됩니다. 그래서 래퍼를위한 래퍼를 얻습니다. "액세스"는 템플릿 매개 변수 T (예 : 읽기 Base.member)에 의존하는 경우

0

글쎄, 당신은 그것을 어떻게 든를 제공해야합니다. 파생 클래스 중 하나로 캐스팅하는 것이 한 가지 방법이지만 reinterpret_cast은 필요하지 않습니다. 당신은 제대로 대체 성 작업을 차단을 방지하기 위해, 포인터/참조를 사용하여 시작하도록해야합니다

Wrapper *a, *b; 
a = new DerivedA; 
b = new DerivedB; 

int a_member = static_cast<DerivedA*>(a)->member; 
float b_member = static_cast<DerivedB*>(b)->member; 

을 그리고 당신이 다형성 할 Wrapper에 가상 메서드를 추가하는 경우, 당신은 동적 캐스트 할 수 있습니다

DerivedB* b_derived = dynamic_cast<DerivedB*>(b); 
if (b_derived != nullptr) { 
    float b_member = b_derived->member; 
    // ... 
}