MFC

RTTI의 이해

디버그정 2008. 9. 2. 07:53

RTTI의 이해

RTTI는 Run-Time Type Information의 약자로써, 실행시간에 객체의 타입 정보를 얻게 하는 C++의 확장? 정도 이다.
자바나 C#의 경우에는 리플렉션의 축소판 정도라고 생각하면 되겠다.

우선은 RTTI를 위하여 구현해야 하는 기능을 보자.

- 실행 시에 알려지지 않은 클래스의 이름과 크기를 얻을 수 있어야 한다.
- 실행 시에 알려지지 않은 클래스를 동적으로 생성할 수 있어야 한다.


우선 실행 시에 클래스의 이름을 얻는 방법부터 보자.
이를 위해서는 딱 두가지의 처리만 해주면 된다.

1. 자신의 클래스의 이름을 저장하는 정적변수를 만든다.
2. 그 이름을 리턴하는 GetClassName()을 오버라이드(override)한다.

소스로 보는 것이 더 확실할 것이다.

class CObject {
public:
    // 자신의 클래스이름을 반환하는 메서드를 만든다.
    virtual char* GetClassName() const { return NULL; }
};

class CSomeObject : public CObject {
public:
    // 자신의 클래스 이름을 반환하는 메서드를 오버라이드한다.
    virtual char* GetClassName() const { return lpszClassName; }

    // 자신의 클래스의 이름을 저장하는 정적변수를 만든다.
    static char lpszClassName[];
};

char CSomeObject::lpszClassName[] = "CSomeObject";

void main() {
    // 사용하는 방법.
    CObject *p;
    p = new CSomeObject;
    cout << p->GetClassName(); // 동적으로 만들어진
                                               // 클래스의 이름을 알 수 있다!!
    delete p;
}

실행결과는 다음과 같을 것이다.

CSomeObject

이것을 매크로로 정의하여 편하게 사용하여 보자.

그 매크로는 바로 두구두구두구두구!!!!

DECLARE_CLASSNAME(s)
IMPLEMENT_CLASSNAME(s)

위의 두 매크로들이다.

선언은 아래와 같이 되어있다.

#define DECLARE_CLASSNAME(s) static char lpszClassName[]
#define IMPLEMENT_CLASSNAME(s) char s##::lpszClassName=(#s)

간단하게 사용하는 예제를 적어본다.
(위의 예제와 똑같은 것이므로 주석은 안 달았다.)

class CObject {
public:
    virtual char* GetClassName() const { return NULL; }
};

class CSomeObject : public CObject {
public:
    DECLARE_CLASSNAME(CSomeObject);
    virtual char* GetClassName() const { return lpszClassName; }
};
IMPLEMENT_CLASSNAME(s);

void main() {
    CObject *p;
    p = new CSomeObject;
    cout << p->GetClassName();
    delete p;
}

이제 실행 시에 클래스의 이름을 알아내는 방법은 알았다.

책에서는 저렇게 하였으나, 개인적인 생각으로는
 DECLARE_CLASSNAME(s) 매크로를

#define DECLARE_CLASSNAME(s) static char lpszClassName[];
                   virtual char* GetClassName() const { return lpszClassName; }

으로 하는 것이 나을 꺼 같다.


-------------------------------------------------------------------------------


이제 동적 생성을 지원하기 위한 조건을 알아보도록 하겠습니다.

우선 동적 생성을 지원하는 클래스를 만들기 위해서
코드 자동 생성기가 해야 하는 작업을 구체적으로 살펴보면,

1. 객체의 클래스 이름을 알 수 있어야 되며,
2. 객체의 크기를 알 수 있어야 되며,
3. 클래스를 동적으로 생성하기 위한 함수를 갖어야 한다.

위의 작업이 가능하도록 구조체를 만들어 봅니다.

struct CRuntimeClass {
    char m_lpszClassName[21]; // 객체의 클래스 이름
    int m_nObjectSize;            // 객체의 크기
    CObject* (*pfnCreateObject)();  // 실제 객체를 생성하기 위한 함수 포인터
    CObject* CreateObject;            // 객체를 생성하기 위한 함수(인터페이스)
};

// 단순히 pfnObject 함수포인터를 랩핑(wrapping)한다.
CObject* CRuntimeClass::CreateObject() { return (*pfnObject)(); }