2010-07-04 4 views
3

가상 상속에 관한 Wikipedia 기사를 읽었습니다. 나는 전체 기사를 따라하지만 난 정말 사이의 오프셋이 있기 때문에 (또는 "vpointer"참조) vtable에 포인터 포유류와 WingedAnimal을 제공함으로써 구현된다C++의 가상 상속

마지막 단락, 예를 들어, 메모리를 따르지 수 포유 동물의 시작과 그것의 동물 부분은 런타임까지 알 수 없습니다. 따라서 Bat은 (vpointer, Mammal, vpointer, WingedAnimal, Bat, Animal)이됩니다. 사실 이 Animal을 상속하는 상속 계층 구조에 대해 하나씩 두 개의 vtable 포인터가 있습니다. 이 예에서는 Mammal의 경우 이고 WingedAnimal의 경우 하나입니다. 오브젝트 크기가 두 포인터만큼 증가한 이지만, 이제 동물은 하나 뿐이며, 모호성은 없습니다. Bat 유형의 모든 객체는 동일한 vpointers를 갖지만 각 Bat 객체는 고유 한 동물 객체를 포함합니다. 그들은 여전히 본질적으로 동일 할 수 있지만 같은 다람쥐와 같은 포유 동물에서 상속은, 다음, 다람쥐의 포유류 객체의 vpointer는 박쥐의 포유류 개체의 vpointer 다른 될 것입니다 다른 클래스, 만약 동물의 다람쥐 이 박쥐 부분과 동일한 크기 인 특별한 경우, 동물원에서 부분까지의 거리가 같기 때문에 이 동일합니다. vtable은 실질적으로 동일하지 않지만 은 모두 정보 (거리)입니다.

누군가이 문제에 대해 좀 더 밝힐 수 있습니까?

답변

6

때로는 일부 코드/다이어그램을 볼 필요가 있습니다.이 표준에 대한 구현 세부 사항에 대한 언급은 없습니다.모든

먼저, C++의 메소드를 구현하는 방법을 보자 :

struct Base 
{ 
    void foo(); 
}; 

이 유사합니다

struct Base {}; 

void Base_foo(Base& b); 

그리고 사실

, 당신은 디버거 내에서 메서드 호출을 볼 때 첫 번째 매개 변수로 종종 this 인수가 표시됩니다. 때로 암시 적 매개 변수라고도합니다.

이제 가상 테이블을 참조하십시오. C와 C++에서 함수 포인터를 사용할 수 있습니다. 상속에에,

void func() 
{ 
    Base b; 
    (*gBaseVTable.mSetter)(b, 3); 
    std::cout << (*gBaseVTable.mGetter)(b) << std::endl; // print 3 
} 

지금 :

struct Base 
{ 
    int a; 
}; 

void Base_set(Base& b, int i) { b.a = i; } 
int Base_get(Base const& b) { return b.a; } 

struct BaseVTable 
{ 
    typedef void (*setter_t)(Base&, int); 
    typedef int (*getter_t)(Base const&); 

    setter_t mSetter; 
    getter_t mGetter; 

    BaseVTable(setter_t s, getter_t g): mSetter(s), mGetter(g) {} 
} gBaseVTable(&Base_set, &Base_get); 

지금 내가 뭔가를 할 수 있습니다의 vtable은 본질적 기능에 대한 포인터의 테이블입니다.

void func() 
{ 
    Derived d; 
    (*gDerivedBaseVTable.mSetter)(d, 3); 
    std::cout << (*gDerivedBaseVTable.mGetter)(d) << std::endl; // print 4 
} 

을하지만 어떻게이 문제를 자동화 :의 다른 구조

struct Derived: Base {}; // yeah, Base does not have a virtual destructor... shh 

void Derived_set(Derived& d, int i) { d.a = i+1; } 

struct DerivedBaseVTable 
{ 
    typedef void (*setter_t)(Derived&,int); 
    typedef BaseVTable::getter_t getter_t; 

    setter_t mSetter; 
    getter_t mGetter; 

    DerivedBaseVTable(setter_t s, getter_t g): mSetter(s), mGetter(g) {} 
} gDerivedBaseVTable(&Derived_set, &Base_get); 

그리고 사용을 만들어 보자?

  • 당신은 비록 당신이 정말로 액세스 할 수 없습니다 (첫 번째 속성으로 vtable에 대한 포인터를 포함 적어도 하나의 가상 함수를
  • 클래스의 각 인스턴스를 가진 클래스 당 VTABLE의 인스턴스가 필요합니다 그것 스스로)

이제 다중 상속의 경우 어떻게됩니까? 음, 상속은 매우 메모리 레이아웃의 용어의 구성과 같다 :

|          Derived         | 
|     BaseA     |     BaseB     | 
| vpointer | field1 | field2 | padding? | vpointer | field1 | field2 | padding? | 

따라서 MostDerived 2 개 가상 테이블이있을 것 하나는 BaseB에서 방법을 변경 BaseA 하나의 방법을 변경할 수 있습니다.

순수 가상 기능은 일반적으로 해당 필드에서 null 포인터 (간단히)로 표시됩니다.

그리고 마지막으로, 생성과 소멸 :

건설

  • BaseA가 구성된다 : 먼저 vpointer 초기화 한 후 속성, 다음 생성자의 본문 구성되어
  • BaseB
  • 을 실행 : vpointer, 특성, 본문
  • Derived 구성 : vpointer (둘 다), 특성, 본문 바꾸기

파괴

  • Derived is destructed : 몸
  • BaseA가 파괴되는 속성 : 소멸자의 몸은, 기본 다시
  • BaseB가 파괴되어 vpointers를 넣어 속성을 파괴 몸,
속성

꽤 포괄적이라고 생각합니다. 주위의 일부 C++ 전문가가 이것을 검토하고 I ha를 확인할 수 있다면 기쁠 것입니다. 바보 같은 실수는하지 마라. 또한 누락 된 부분이 있으면 추가 할 수있어서 기쁩니다.

+0

정말 포괄적 인 답변입니다! 고마워요! – Bruce

+0

가상 상속 중 어떤 일이 발생합니까? 그리고 가상 상속 후 Bat가 (vpointer, Mammal, vpointer, WingedAnimal, Bat, Animal)이된다는 것을 어떻게 설명합니까? – Bruce

+1

여기서 '박쥐'는 오류입니다 (무한 재귀를 일으킴). 무시하십시오. '가상'상속의 경우 가상으로 상속받은 클래스는 (가장 많이 파생 된 클래스에 의해) 한번만 인스턴스화되지만'Mammal'과'WingedAnimal' 부분 전에 분명하게 인스턴스화됩니다. –

6

나는 정말로 할 수 없다. 이 절에서는 다중 상속의 경우 동적 바인딩을 제공하기 위해 가상 메소드 테이블을 사용하여 C++ 구현에서 수행해야 할 작업을 설명하려고합니다.

컴파일러를 수행하지 않는 경우 제 조언은 다음과 같습니다. 신경 쓰지 마세요. 상속, 가상 메소드, 여러 상속 및 가상 상속에 대한 C++ 책을 읽으십시오.

게다가 vtable의 사용은 C++ 표준 (IIRC)에서 필요하지 않습니다. 이는 구현 세부 사항입니다. 그래서 정말로, 신경 쓰지 마라.

+0

실제로 vpointers를 설명하는 답변을 쓰기 시작했으나 전체 책을 읽지 않으려는 경우가 아니라면 대답은 아마도 더 좋습니다. –

+0

@ Fogh :이 문제는 오랫동안 나를 괴롭혔다 ... 나는 전체 책을 읽는 것을 꺼린다. – Bruce

1

mkluwe가 제안했듯이 vpointers는 실제로 언어의 일부가 아닙니다. 그러나 약 구현 기술을 아는 것이 유용 할 수 있습니다. 특히 C++와 같은 저급 언어에서 유용 할 수 있습니다.

이 내용을 실제로 배우고 싶다면 Inside the C++ Object Model을 권하고 싶습니다.이 내용과 다른 많은 것들을 자세히 설명합니다.

+0

@Fogh : 많이 고마워요. – Bruce