|
장성호 님이 쓰신 글 :
: MethodAddress 함수 써보신분 계신가요?
:
: TObject의 MethodAddress 메소드는 반환값이 void* 입니다.
: VCL에 객체멤버함수의 포인터인 8Byte가 아니라
: win32시스템에 기본형인 4Byte짜리 void * 인것입니다.
:
: void *로 받아서 형변환해서 함수 호출하면
: 객체 내부에서 호출되는것이 아니라 이상하게 호출됩니다.
:
: 아래코드에서 Button2Click 과 Button3Click 을 하면 어떻게 나타날가요?
:
: Button2Click 하면 "Form2"가 ShowMessage되고
: Button3Click 하면 "Button3"가 ShowMessage됩니다. 이런 황당한...
:
: 단지 호출할때 Sender를 Form2와 Button3로 다르게 넘겨준것인데...
:
: 왜그런거죠?
: 1. 왜 Button1Click 함수내에서 Sender가 this가 되버린거죠?
: 2. 왜 MethodAddress 는 Published만 찾을수 있는거죠? ( 그렇게 만들어 놓았기때문이라는 답변 말구요)
: String으로 객체멤버함수를 찾을수는 없는건가요? 그렇다면 왜 그런지요?
:
: 누가 MethodAddress에 대해 좀 자세히 가르쳐 주세요
:
: FieldAddress 도 같은 원리인것 같은데 같이 설명좀...
:
:
: [MethodAddress 사용예]
:
: void __fastcall TForm2::Button1Click(TObject *Sender)
: {
: ShowMessage(this->Caption);
: }
: //---------------------------------------------------------------------------
: typedef void __fastcall ( *TObjectEvent)(System::TObject* Sender);
: void __fastcall TForm2::Button2Click(TObject *Sender)
: {
: TObjectEvent BtnClick;
: void *tt=MethodAddress(this->ClassType(), "Button1Click"); //or MethodAddress( "Button1Click");
: BtnClick=(TObjectEvent)tt;
: if(BtnClick)BtnClick(this);
: }
: //---------------------------------------------------------------------------
: void __fastcall TForm2::Button3Click(TObject *Sender)
: {
: TObjectEvent BtnClick;
: void *tt=MethodAddress(this->ClassType(), "Button1Click");// or MethodAddress( "Button1Click");
: BtnClick=(TObjectEvent)tt;
:
: if(BtnClick)BtnClick(Sender);
: }
: //---------------------------------------------------------------------------
:
: 미리 감사드립니다.
BtnClick는 TForm2의 멤버 함수로 호출된 게 아니고 비 멤버 함수로 호출되었습니다.
멤버 함수로 호출 될 때는 클래스의 인스턴스 포인터를 스택에 저장해두고 해당 함수로 넘어가고
해당 함수 내에서 그 것을 꺼내서 this 포인터로 사용합니다.
BtnClick의 경우는 멤버 함수로 호출되지 않았으므로 클래스의 인스턴스 포인터가 스택에 들어가 있지 않은 상태에서 호출되게 되고 해당 함수 내부에 진입되었을 때 스택에서 꺼내게 되는 this 포인터는 엉뚱한 값이 됩니다.
(지금의 경우 함수의 첫번째 매개변수가 this 포인터로 오인됩니다)
따라서, 아래와 같이 우회할 수도 있으나 표준은 아니며 함수호출규약에 따라 작동하지 않을 수도 있습니다.
typedef void __fastcall ( *TObjectEvent)(TForm2*, System::TObject* Sender);
if(BtnClick)BtnClick(this,this);
if(BtnClick)BtnClick(this,Sender);
아래와 같은 형변환이 허락된다면 좋겠지만 허락되지 않는군요.
typedef void __fastcall (TForm2::*Method)(System::TObject* Sender);
Method m1 = (Method)MethodAddress(this->ClassType(), "Button1Click");
if(m1) (this->*m1)(Sender);
MethodAddress는 컴파일 시간이 아닌 실행 시간에 메서드 이름으로 그 주소를 구하는 것이므로
Published만 가능하다면 실행시간에는 Published 외에는 이름 정보가 없는 것으로 보입니다.
컴파일 링크 과정에서 함수는 이름으로 저장되지 않고 주소로 바뀌어 저장되는데 Published는 이름도 함께 저장되는 모양입니다.
|