2010-05-25 7 views
5

기존 기능을 그대로두고 일부 코드를 리팩토링하려고합니다. 개체에 대한 포인터를 기본 인터페이스로 캐스팅하고 나중에 파생 클래스를 가져 오는 데 문제가 있습니다. 프로그램은 경우에 따라 팩토리 객체를 사용하여 이러한 객체의 인스턴스를 만듭니다.다중 상속을 사용하여 클래스를 캐스팅 할 수 없습니다.

다음은 내가 작업중인 클래스의 몇 가지 예입니다.

// This is the one I'm working with now that is causing all the trouble. 
// Some, but not all methods in NewAbstract and OldAbstract overlap, so I 
// used virtual inheritance. 
class MyObject : virtual public NewAbstract, virtual public OldAbstract { ... } 

// This is what it looked like before 
class MyObject : public OldAbstract { ... } 

// This is an example of most other classes that use the base interface 
class NormalObject : public ISerializable 

// The two abstract classes. They inherit from the same object. 
class NewAbstract : public ISerializable { ... } 
class OldAbstract : public ISerializable { ... } 

// A factory object used to create instances of ISerializable objects. 
template<class T> class Factory 
{ 
public: 
    ... 
    virtual ISerializable* createObject() const 
    { 
     return static_cast<ISerializable*>(new T()); // current factory code 
    } 
    ... 
} 

This question 주조의 종류가하는 일에 대한 좋은 정보를 가지고 있지만 나를이 상황을 파악 도움이 아니에요. static_cast와 일반 캐스팅을 사용하면 error C2594: 'static_cast': ambiguous conversions from 'MyObject *' to 'ISerializable *'이됩니다. dynamic_cast를 사용하면 createObject()가 NULL을 반환합니다. NormalObject 스타일 클래스와 이전 버전의 MyObject는 공장에서 기존 static_cast와 함께 작동합니다.

이 캐스트 작업을 수행 할 수있는 방법이 있습니까? 그것은 가능한 것처럼 보입니다.

답변

10

사실은 ISerializable에서 상속받습니다 (방금 VS2010으로 테스트했습니다). 이것은 다이아몬드 문제이라고하는 일반적인 문제이며 컴파일러는 계층 구조 경로를 알지 못합니다.

편집이 :

이 그것을 수행해야합니다

class NewAbstract : public virtual ISerializable { ... } 
class OldAbstract : public virtual ISerializable { ... } 
+0

+1 : 이것은 gcc에도 적용됩니다. – Troubadour

+3

FAQ에서 권장하는 솔루션과 정확히 일치 : http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.8 –

+0

해결되었습니다.나는 초록이 사실상 상속 할 필요가 있다는 것을 깨닫지 못했습니다. @ 마크 랜섬, 훌륭한 링크에 감사드립니다. 전체 페이지가 매우 도움이됩니다. –

-2

"두려워한 다이아몬드"와 가상의 상속을 찾으십시오. 그들은 당신을 도울 수 있습니다.

+0

링크가 포함 된 경우이 +1을 부여했습니다. –

+2

여기에 나온 답변은 특정 질문에 대한 정확한 답변을 제공하는 것이 아니라 포스터에게 답변 조사 방법을 알려줌으로써 자세히 알아보고 다음 번에 답변 할 수 있도록하는 방법에 관한 것입니다. 왜 유용 할 수있는 링크가 많을 때 링크를 제공합니까? 어쩌면 이런 식으로 뭔가 : http://tinyurl.com/2cermbg? 무의미하게 무례하고 불필요한 것 같습니다. –

+0

직접적으로 여기에 링크를 게시 할 수 없다면 너무 나쁩니다. ;) –

0

사실상 NewAbstract와 OldAbstract에서 상속하지 마십시오. 하나를 선택하여 사실상 상속받습니다. 나는 그것이 그것을 돌볼지도 모른다라고 생각한다.

+2

사실상 어느 쪽도 상속하지 마십시오. 그들은 공통 기본 클래스 (ISerialiazable)를 상속 받아야합니다. –

1

먼저 즉각적인 기지 중 하나 예를 캐스팅하여 피해 갈 수 있습니다.

virtual ISerializable* createObject() const 
{ 
    NewAbstract*const na = dynamic_cast< NewAbstract* >(new T()); 
    return dynamic_cast< ISerializable* >(na); 
} 
+0

작동하는 것처럼 들립니다. 비록 내가 여기 읽은 다른 것들에서, 당신은 이것에 정말로주의를 기울여야 할 것처럼 보입니다. 어쨌든이 특별한 이슈의 경우 NewAbstract는 팩토리 객체가 알아야 할 것이 아닙니다. –

+0

@Jay : 예, @ Simon의 답변을 보았을 때 그것이 올바른 일임을 깨달았습니다. 가상 상속이 잘못된 장소에 있다는 사실을 놓쳤습니다. 나는 그것이 쓰레기 일지라도 대답을 지우는 것을 좋아하지 않으므로 여기에 그것을 남겨 뒀다 ...;) – Troubadour