아젠더 님이 쓰신 글 :
: 빌더님 답변해주신거 감사합니다.
:
: class TSomeClass : public TObject
: {
: public:
: __fastcall TSomeClass(){}
: __classmethod TObject* __fastcall NewInstance()
: {
: OutputDebugStringA("called.....");
: TObject::NewInstance();
: }
: };
: //---------------------------------------------------------------------------
: void __fastcall TForm1::Button1Click(TObject *Sender)
: {
: TSomeClass *p = new TSomeClass();
: }
:
: 제가 __classmethod 부분이 생소한데요.
: 저렇게 TObject::NewInstance()로 클래스 지정자를 통해서 호출하는걸 보면
: NewInstance가 static 멤버함수여야 할거 같은데요. 표준 C++에서 static 멤버함수와 다른 건가요.
: __classmethod 부분이 이해가 안됩니다. 설명좀 부탁드립니다. 빌더님.
답변:
class TSomeClass
{
public:
static void Foo()
{
}
};
TSomeClass::Foo(); // 객체의 생성 없이 함수사용
TSomeClass *obj = new TSomeClass();
obj->Foo(); // 에러
클래스의 static 멤버함수는 위와 같은 식으로 객체를 생성하지 않고 사용하게 됩니다.
static 멤버함수는 객체의 인스턴스로 참조될 수 없고, 또 함수정의 안에서 클래스 데이타 멤버에 대한 액세스도
허용되지 않습니다. 그렇기 때문에 static 멤버함수 안에선 this 포인터도 사용할 수 없고요.
표준 C++에서 static 멤버함수의 의미는 그렇습니다.
__classmethod 의 경우는 다릅니다.
class TSomeClass : public TObject
{
public:
__fastcall TSomeClass(){}
__classmethod String __fastcall GetMyClassName()
{
return UTF8ToString(*PShortString(*PPointer(System::PByte(this) - 56)));
}
};
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
// 1. static 멤버함수 처럼 객체의 인스턴스 없이 사용할 수도 있고
Caption = TSomeClass::GetMyClassName();
// 2. 객체를 생성해서 인스턴스로 참조해서 사용할 수도 있다
TSomeClass *obj = new TSomeClass();
Caption = obj->GetMyClassName();
delete obj;
}
위와 같이 __classmethod 키워드로 정의되어있는 GetMyClassName() 의 경우에...
클래스 객체의 인스턴스 없이 함수의 사용이 가능하므로... 표준 C++에서 static 멤버함수와 같은 의미라고 볼수도
있습니다. 그런데 __classmethod는 위와 같이 객체의 인스턴스로 참조하는 것도 가능합니다. 그런면에서 보면
__classmthod는 표준 C++ 언어에서의 static 멤버함수 역할도 하고... 또 위와 같이 참조가 가능해서 클래스 본연의
멤버함수 역할을 겸하기도 합니다.
기존에 Visual Studio C/C++ 또는 리눅스에서 GCC 같은 표준 C++ 랭귀지만 사용해온 분들 한테는 __clasmethod
가 조금은 생소하게 여겨질 텐데요.
아마도 대부분의 사람들이 __classmthod 라는 게 있는지도 모른 채 델파이나 C++빌더로 코딩하고 있을 겁니다.
컴포넌트에 의존해서 코딩하는 게 전부라면 더 그렇지 않겠습니까.
그러나 VCL 프레임웍 내부에서 __classmthod 는 아주 중요한 역할을 하게되는 데요.
클래스 타입정보 만을 갖고 객체를 동적으로 생성할 수 있게 해주는 역할 입니다. 이 부분은 답변으로 다루기엔
다뤄야 할 내용이 너무 많고... 간략하게 __classmethod String __fastcall GetMyClassName()를 예로 들어 볼게요.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
// static 멤버함수 처럼 객체의 인스턴스 없이 사용하는 경우
Caption = TSomeClass::GetMyClassName();
위와 같이...
TSomeClass ::GetMyClassName() 을 호출 하면...
컴파일러는 GetMyClassName() 함수가 __classmethod 로 정의 되어있다는 것을 알고, 어떤 숨겨진 히든 파라미터를
함수에 넘겨주는 코드를 생성하게 되는데....
여기서 히든 파라미터는 TSomeClass의 클래스타입 정보를 가르키는 포인터 입니다. RTTI 정보죠.
컴파일러가 생성하는 RTTI 정보는 다양한 섹션을 포함하고 있는데, 섹션 테이블에서 VMT를 Zero Base로 사용합니다.
다시 위의 코드를 끌어 내려서 보죠,..
class TSomeClass : public TObject
{
public:
__fastcall TSomeClass(){}
__classmethod String __fastcall GetMyClassName()
{
return UTF8ToString(*PShortString(*PPointer(System::PByte(this) - 56)));
}
};
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
// 1. static 멤버함수 처럼 객체의 인스턴스 없이 사용할 수도 있고
Caption = TSomeClass::GetMyClassName();
// 2. 객체를 생성해서 인스턴스로 참조해서 사용할 수도 있다
TSomeClass *obj = new TSomeClass();
Caption = obj->GetMyClassName();
delete obj;
}
GetMyClassName() 이 호출되면, 이 클래스 메소드는 화면에 "TSomeClass" 라는 클래스 네임을 표시할 겁니다.
return UTF8ToString(*PShortString(*PPointer(System::PByte(this) - 56)));
메소드에서 어떻게 클래스 네임을 알아서 표시할 수 있었을까요?
위에서 언급한대로... 클래스 타입에 대한 히든(Hidden) 파라미터를 컴파일러가 넘겨줬기 때문입니다.
-56 은 컴파일러가 생성한 RTTI 섹션 테이블에서 VMT를 Zero base로 하는 'Class Name' 필드에 대한
Relative 인덱스 값이고요.
우선은..
__classmethod는... 표준 C++에서의 static 멤버함수와 같은 symantic 으로 사용 되기도 하지만...
히든 파라미터로 클래스 타입에 대한 정보도 같이 받게 되는... 컴파일러에 의해서 특별히 취급되는 메소드라고
알아 두세요.
.....