2017-12-01 2 views
0

저는 나쁜 클래스 계층 구조와 같은 끔찍한 문제에 조금 빠져 있습니다. 실제 기본 클래스가 아닌 업 캐스팅

class A {...}; // abstract 
class B : public A {...}; // abstract 
class C {...}; // abstract 

class a1 : public B, public C {...}; // indirect inheritance of A 
class c1 : public A, public C {...}; 

질문 : 그것은 가능한 내가 가장 좋은 방법은 C가 A로부터 상속 단지 클래스를 만드는 것을 이해

클래스 A에 포인터 (참조)로 C에 대한 포인터를 (참조)로 변환하지만, 여전히 클래스 a1 (두 개의 기본 A)에 문제가 발생할 수 있습니다.

+0

C와 A는 그렇게 아니, 정적 캐스트와 2 사이의 변환을 할 수없는, 전혀 관련이 있습니다.그래도 변환 연산자를 만들 수 있습니다 (또는 방금 다시 디자인 할 수 있음) – UKMonkey

답변

3

질문 :이 가능한 적어도 하나 개의 가상 멤버 함수가 클래스 A. 포인터 (참조)로 C 포인터 (참조)을 변환

없음 클래스, 즉 다형 아니라면이다. 이 경우 dynamic_cast를 StoryTeller의 답변에 표시된대로 사이드 캐스팅에 사용할 수 있습니다.

C 포인터 (참조)가 A을 상속 한 하위를 가리킨 경우 해당 하위 포인터로 먼저 캐스팅 한 다음 A으로 캐스팅 할 수 있습니다. 당신은 누구의 구체적인 유형 알 수없는 단지 임의의 C 포인터를 변환 할 수 없기 때문에 반드시 물론 이상적인 아니다

c1 c; 
C& cref = c; 
A& aref = static_cast<c1&>(cref); 

.

내가 가장 좋은 방법은 C 당신이 이런 짓을하면

에서 상속 단지 클래스를 만드는 것입니다 이해, 모든 C 포인터는 A 포인터로 암시 적으로 변환 될 것이다.

그러나 여전히 클래스 a1 (두 개의 기본 A)에 문제가 발생할 수 있습니다.

문제를 해결하려면 공유 상거래 즉 가상 상속이 필요합니다.

struct A {}; // abstract 
struct B : virtual A {}; // abstract 
struct C : virtual A {}; // abstract 

struct a1 : B, C {}; // indirect inheritance of A 
struct c1 : C {}; 

int main() { 
    c1 c; 
    C& cref = c; 
    A& aref = cref; 
} 
3

당신이하려고하는 것을 "사이드 캐스트"라고합니다. 그리고 내장 된 dynamic_cast 표현은 그렇게 할 수 있습니다. 하지만 싸구려가 아니므로 프로젝트에서 RTTI에 대한 지원을 해제하지 않는 것이 좋습니다. 이미 클래스가 추상 클래스라고 언급 했으므로 RTTI가 생성되기 위해 선언이 필요한 가상 함수가 필요합니다.

Live

#include <cassert> 

struct A { 
    virtual ~A() = default; 
}; 

struct B : public A { 
    virtual ~B() = default; 
}; 

struct C { 
    virtual ~C() = default; 
}; 

struct a1 : public B, public C { 
    a1() = default; 
    virtual ~a1() = default; 

}; // indirect inheritance of A 

int main() { 
    a1 a; 

    C* c = &a; 

    assert(dynamic_cast<A*>(c) != nullptr); 

    return 0; 
} 

하지만 클래스를 재 설계 할 필요에 대해 감정이 매우 보증 내 의견에 참조하십시오. 사이드 캐스트를 할 필요가 없습니다.

+0

dynamic_cast를 허용하려면 가상 멤버 함수를 추가해야한다는 점을 명시 적으로 언급합니다. – user2079303

+0

@ user2079303 - 감사합니다. 가정을 명시 적으로 지정했습니다. 나는 그 수업이 추상적이라고 말하는 OP에서 벗어나려고했다. – StoryTeller

0

위의 두 대답은 모두 정확하지만 첫 번째 설명은 더 광범위하게 설명됩니다. 나는 아마도 같은 이상한 방문자를 만드는 사용 또 다른 해결책 :

PointerCreator 
{ 
    void visit (const a1 & _a) 
    { 
    m_pointerToA = &_a; 
    } 

    void visit (const c1 & _c) 
    { 
    m_pointerToA = &_a; 
    } 

    A * m_pointerToA; 
}; 

PointerCreator pC; 
a1.accept(pC); 
A& = *pC.m_pointerToA; 
+0

음, 아마도 언젠가는 유용 할 수도 있지만 ... 보통의 방법으로는 생각하지 않을 것입니다. 방문자를 사용하는 경우 방문객이 특정 조치를 취하는 것을 선호 할 수 있습니다. 즉, 대상이 없거나 여러 대상을 적절하게 처리 할 수 ​​있기 때문입니다. – Phil1970

관련 문제