ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 클래스 맴버함수의 함수 포인터
    Computer Language/C 2007. 8. 24. 16:41
    728x90
    일반적으로 함수 포인터는 void* 로 캐스팅되지 않는다. 
    • 이는 type 이나 value 보다는 name 에 instantiation 되기 때문이다.
    일반적으로 맴버 함수 포인터는 일반 함수 포인터와 다르다. 
    • 일반적으로 콜링컨벤션은 __cdecl, __stdcall, __fastcall 이 있는것으로 알려져 있으나 하나가 더 존재한다. 그것은 바로 __thiscall
    • 맴버 함수 포인터는 특이하게 스코프(::*) 가 들어가 있다. (__thiscall 과 관련있음)
    • 따라서 선언할때 아주 눈게 거슬리게 선언이 된다. (그래서 보통 typedef 로 짧게 만들어 놓고 씀)
    문제는 다중 상속일때 발생한다. 
    • 단일 상속을 하게 되면 상속받은 클래스의 엔트리 포인트를 상속한 클래스의 엔트리로 변경하는 야매로 맴버함수 포인터를 사용할 수 있다.
      class A { void a(); }; class B : public A { void b(); }; // 여기서 B::a() 의 포인터를 선언하면 모양새는 B::a() 가 되지만 실제 값은 B 대신 A가 들어가 있다. 자연히 A::a()가 호출됨
    • 문제는 다중상속인데 이를 해결하기 위해 함수 포인터에 offset 이용함
    • offset 때문에 맴버함수포인터의 size 가 기존 포인트size 보다 커지게 됨.
    • VC++일 경우 포인터 크기는 아래와 같음

    int : 4 byte
    data pointer : 4
    code pointer : 4
    단일상속맴버 pointer : 4
    다중상속맴버 pointer : 8
    Virtual 맴버 pointer : 12
    Unknown pointer : 16


    일반적으로 MFC에 메시지맵(맴버가상함수포인터상속한뒤캐스팅을 활용한 대표적인예) 에서는 어떤 야매를 썼나 
      union MessageMapFunctions 
    { 
    	AFX_PMSG pfn; 	// generic member function pointer   
    			// specific type safe variants for WM_COMMAND and WM_NOTIFY messages 
    	void (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND)(); 
    	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_bCOMMAND)(); 
    	void (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND_RANGE)(UINT); 
    	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND_EX)(UINT);   
    	void (AFX_MSG_CALL CCmdTarget::*pfn_UPDATE_COMMAND_UI)(CCmdUI*); 
    	void (AFX_MSG_CALL CCmdTarget::*pfn_UPDATE_COMMAND_UI_RANGE)(CCmdUI*, UINT); 
    	void (AFX_MSG_CALL CCmdTarget::*pfn_OTHER)(void*); 
    	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_OTHER_EX)(void*);
     
    • 위와 같은 엄청난 분량의(나올수 있는 가능성이 있는 모든 함수) 포인터를 union 으로 묶었다.

    댓글

Designed by black7375.