2009-11-26 2 views

답변

10

MSCV는 one vptr per object and one vtbl per class을 사용하여 RTTI 및 가상 함수와 같은 OO 메커니즘을 구현합니다.
RTTI와 가상 함수는 vptr이 올바르게 설정된 경우에만 제대로 작동합니다.

struct __declspec(novtable) B { 
    virtual void f() = 0; 
}; 
struct D1 : B { 
    D1() { 
    }  // after the construction of D1, vptr will be set to vtbl of D1. 
}; 
D1 d1;  // after d has been fully constructed, vptr is correct. 
B& b = d1; // so virtual functions and RTTI will work. 
b.f();  // calls D1::f(); 
assert(dynamic_cast<D1*>(&b)); 
assert(typeid(b) == typeid(D1)); 

__declspec(novtable)을 사용할 때 B는 추상 클래스 여야합니다.
D1의 생성자를 제외하고는 B의 인스턴스가 없습니다.
그리고 __declspec (novtable)에는 대부분의 경우 부정적인 영향이 없습니다.

그러나 파생 클래스 __declspec(novtable)의 건설 중에는 ISO C++ 의미와 달라집니다.

struct D2 : B { 


    D2() { // when enter the constructor of D2 \ 
      //  the vtpr must be set to vptr of B \ 
      //  if B didn't use __declspec(novtable). 
      // virtual functions and RTTI will also work. 

      this->f(); // should calls B::f(); 
      assert(typeid(*this) == typeid(B)); 
      assert(!dynamic_cast<D2*>(this)); 
      assert(dynamic_cast<B*>(this)); 

      // but __declspec(novtable) will stop the compiler \ 
      // from generating code to initialize the vptr. 
      // so the code above will crash because of uninitialized vptr. 
    } 
}; 

참고 : virtual f() = 0; f를 pure virtual function으로, B를 추상 클래스로 만듭니다.
순수 가상 함수 could (must)의 definition이 누락되었습니다.
C++에서는 권장하지 않는 생성자에서 가상 함수 호출을 허용합니다.

업데이트 : D2의 실수 : 파생 생성자의 vptr.

struct D3 : B { // ISO C++ semantic 
    D3() {  // vptr must be set to vtbl of B before enter 
    }   // vptr must be set to vtbl of D2 after leave 
}; 

그러나 vptr은 생성 중에 불확정합니다. 이것은 생성자에서 가상 함수 호출이 권장되지 않는 이유 중 하나입니다.

D2 :: D2()의 vptr이 B이고 v :: b (f)의 정의가 누락 된 경우 vtbl의 포인터를 함수로 역 참조 할 때 this->f();이 충돌합니다.
D2 :: D2()의 vptr이 B이고 B가 novtable을 사용하는 경우 초기화되지 않은 vptr을 참조 해제 할 때 this->f();이 중단됩니다.

실제로 D2 :: D2()의 vptr은 MSVC (msvc8)의 D2입니다. 컴파일러는 D2 :: D2()에서 다른 코드를 실행하기 전에 vptr을 D2로 설정합니다.
따라서 this->f();은 D2 :: f()를 호출하며 3 개의 어설 션은 위반됩니다.

+3

기본적으로 이것은 (1) 생성자에서 가상 함수 호출이없고 (2) 순수 가상 함수가 실제로 호출되면 더 이상 "순수 가상 함수 호출"이라는 오류 정보를 얻지 않습니다. – paxos1977

3

정확하게 이해하면 ctor 또는 dtor 내의 가상 fn 호출은 컴파일 타임 링크로 변환됩니다. (c/d) tors에서 가상 fn 호출을 할 수 없습니다. 그 이유는 기본 클래스의 객체가 생성 될 때 파생 된 클래스에 대한 지식이 없으므로 파생 클래스를 호출 할 수 없으며 같은 논리가 적용되는 dtors를 사용할 수 없기 때문입니다.

관련 문제