2013-08-15 3 views
8

위한 도우미 변수 I는 다음 링크에서이 기술을 발견 http://www.codeproject.com/Tips/90875/Displaying-vtable-when-debuggingvoid (** vt)() = * (void (***)()) ptr; C에서 가상 테이블 ++

을 거기에, 그는 가상 함수 테이블을 표시하기 위해

void (**vt)() = *(void (***)())ptr; 

변수 하나 도우미를 사용합니다.

하지만

void (**vt)() = (void (**)())ptr; 

로 변경할 경우 이전 한대로 작동하지 않습니다.

누군가 마법에 관한 설명을 도와 줄 수 있습니까?

답변

3

많은 C++ 구현의 가상 테이블 포인터는 개체의 첫 번째 sizeof(void (**)()) 바이트입니다. 포인터를 역 참조 할 때 실제 가상 테이블의 시작 주소를 가져옵니다. 그것이 작동 코드의 의미입니다.

cdecl 프로그램이 여기에 도움 비트의 수 있습니다 : 첫 번째 코드는 제대로 derefereancable 포인터로 개체 포인터를 캐스트

cdecl> explain void (***foo)() 
declare foo as pointer to pointer to pointer to function returning void 
cdecl> explain void (**foo)() 
declare foo as pointer to pointer to function returning void 

(를 작동하려면 포인터 포인터 포인터, void (***)()) , 그런 다음 가상 테이블의 시작 주소를 얻기 위해 역 참조합니다.이 가상 테이블은 void (*[])() (poin의 배열) 가상 테이블의 시작을 가리키는 유형 void (**)() (에 대한 포인터에 대한 포인터 )입니다. 기능을 수행하려면).

두 번째 것은 객체에 대한 포인터를 void를 반환하는 함수에 대한 포인터에 대한 포인터로 캐스트합니다. 변수 vt에 저장된 주소는 개체의 주소 일뿐입니다.

class Object { 
public: 
    virtual void foo() {}; 
}; 

Object x; 

// is approximately equivalent to 

struct Object { 
    void (**_vtable)(); 
}; 

void _Object_foo(Object this) { 
} 

// this does not really compile, however, 
// because a pointer mismatch 
void (*_vtable_for_Object[])() = { 
    _Object_foo 
}; 

Object y; 
y._vtable = _vtable_for_Object; 

따라서

Object *ptr = new Object(); 
// x now points to a block of memory, 
// whose first bytes are void (**_vtable)() 

// then 
void (**vt)() = *(void (***)())ptr; 

// is equivalent in our analogy to 
void (**vt)() = ptr->_vtable; 

// except that the C++ does not allow you to 
// access the virtual table directly without 
// the trickery of the former 
+0

설명해 주셔서 감사합니다. 매우 계몽! – Alex

8

을함으로써의 명확성에 대한 형식 정의를 소개하겠습니다.

typedef void (**thing)(); 

그런 다음 첫 번째 코드는

thing vt = *(thing*) ptr; 

이고 두 번째

thing vt = (thing) ptr; 

이며, 첫 번째는 일에 대한 포인터로 치료의 PTR "라고, 나를주고 무엇을 두 번째는 "ptr을 일"로 취급합니다.
차이가 분명해야합니다.

이유는 에 모두은 Visual C++ 컴파일러와 Visual Studio 디버거에 매우 한정적입니다.

디버거가 실제로 어떤 유형인지 알지 못하면 디버거가 알고있는 것을 표시합니다. 즉, 기본 클래스의 인스턴스이며 기본 클래스의 vtable에있는 항목 수만 있습니다.

(여기서 중요한 부분은보기 윈도우의 항목에 예상되는 테이블 항목을 추가 한 것입니다. 이렇게하면 디버거가 메모리를 많은 요소의 배열로 표시합니다.)

그래서 트릭은 vtable의 이름을 만들고, 테이블에서 표시 할 요소의 수를 디버거에 알려주는 것으로 구성됩니다.

+0

알렉스가 왜 첫 번째 작품을 알고 싶어한다고 생각합니까? –

+0

@molbdnilo가 문제를 잘 설명했다고 생각합니다. – Alex

관련 문제