문제

단일 상속은 구현하기 쉽습니다. 예를 들어, C에서 상속은 다음과 같이 시뮬레이션 될 수 있습니다.

struct Base { int a; }
struct Descendant { Base parent; int b; }

그러나 여러 상속을 통해 컴파일러는 새로 구성된 클래스 내에 여러 부모를 준비해야합니다. 어떻게 끝났습니까?

내가 일어나는 문제는 다음과 같습니다. 부모가 AB 나 BA로 배열되어야합니까, 아니면 다른 방법으로도 마련되어야합니까? 그리고 내가 캐스트를한다면 :

SecondBase * base = (SecondBase *) &object_with_base1_and_base2_parents;

컴파일러는 원래 포인터를 변경 여부를 고려해야합니다. 가상에서도 비슷한 까다로운 것들이 필요합니다.

도움이 되었습니까?

해결책

C ++의 제작자의 다음 논문은 다중 상속의 가능한 구현을 설명합니다.

C ++에 대한 다중 상속 -Bjarne Stroustrup

다른 팁

거기있었습니다 이 꽤 오래된 MSDN 기사 VC ++에서 구현 된 방법에 대해.

그리고 내가 캐스트를한다면 :

SecondBase base = (SecondBase *) object_with_base1_and_base2_parents;

컴파일러는 원래 포인터를 변경 여부를 고려해야합니다. 가상과 비슷한 까다로운 것들.

비 바이러스 상속의 경우 이것은 캐스트가 컴파일되는 시점에서 컴파일러는 파생 클래스의 정확한 레이아웃을 알고 있습니다 (결국 컴파일러가 레이아웃을 수행했습니다). 일반적으로 발생하는 모든 것은 고정 된 오프셋 (기본 클래스 중 하나의 경우 0 일 수 있음)이 파생 클래스 포인터에서 추가/빼기입니다.

바이러스 상속을 사용하면 조금 더 복잡 할 수 있습니다. VTBL (또는 유사한)에서 오프셋을 잡는 것이 포함될 수 있습니다.

Stan Lippman의 책, "C ++ 객체 모델 내부" 이 물건이 어떻게 작동하는지에 대한 매우 좋은 설명이 있습니다.

부모는 지정된 순서대로 정렬됩니다.

class Derived : A, B {} // A comes first, then B

class Derived : B, A {} // B comes first, then A

두 번째 사례는 컴파일러 별 방식으로 처리됩니다. 일반적인 방법 중 하나는 플랫폼의 포인터 크기보다 큰 포인터를 사용하여 추가 데이터를 저장하는 것입니다.

이것은 실제로 C ++ 구체적이지 않은 흥미로운 문제입니다. 다중 파견과 여러 상속 (예 : Clos)이있는 언어가있을 때 상황이 더욱 복잡해집니다.

사람들은 이미 문제에 접근하는 다른 방법이 있다고 언급했습니다. 이 맥락에서 흥미로운 메타 객체 프로토콜 (MOP)에 대해 조금 읽을 수 있습니다 ...

컴파일러가 어떻게 수행되는지에 따라 전적으로 내려지지 만, 나는 일반적으로 VTables의 상속 구조를 통해 수행 된 것을 믿습니다.

간단한 실험을 수행했습니다.

class BaseA { int a; };
class BaseB { int b; };
class Descendant : public BaseA, BaseB {};
int main() {
        Descendant d;
        BaseB * b = (BaseB*) &d;
        Descendant *d2 = (Descendant *) b;
        printf("Descendant: %p, casted BaseB: %p, casted back Descendant: %p\n", &d, b, d2);
}

출력은 다음과 같습니다.

Descendant: 0xbfc0e3e0, casted BaseB: 0xbfc0e3e4, casted back Descendant: 0xbfc0e3e0

정적 캐스팅이 항상 "콘텐츠를 만지지 않고 유형을 바꾸는 것"을 의미하지는 않는다는 것을 깨닫는 것이 좋습니다. (데이터 유형이 서로 맞지 않으면 컨텐츠에 대한 간섭이 있지만 상황은 다른 IMO입니다).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top