2010년 3월 15일 월요일

실행시간 타입 정보 (RTTI)

 RTTI(RunTime Type Information)는 실행 시간에 객체들의 정보를 얻는 표준화된 방법을 제공합니다.

 

RTTI의 주요 구성 요소

  • type_info 클래스 : 실행 시간에 확인하고자 하는 타입에 대한 정보 저장 클래스.
  • typeid 연산자 :  객체 타입을 식별하고 반환하는 연산자 .
  • dynamic_cast 연산자 : 실행 시간에 실제 객체 타입을 인식하여 형변환하는 연산자.

 

사용시 주의점

  • 보통 컴파일러는 RTTI가 동작하지 않도록 설정되어 있습니다. RTTI가 동작하도록 옵션을 설정해야 합니다. (RTTI를 사용하지 않는 프로그램이 굳이 RTTI 코드를 포함할 필요가 없기 때문에...)
  • 계층 구조상의 클래스 정보를 확인하기 위해서는 클래스에 virtual 함수가 있어야 합니다. ( 다형성을 사용하지 않는 기본 클래스의 RTTI는 별 의미가 없기 때문입니다.)

 

VS2008의 RTTI 설정 그림(프로젝트 메뉴의 속성 페이지)

RTTI_설정.png 

 

 

RTTI 사용 예

#include <iostream>
#include <typeinfo>
using namespace std;
class Parent
{
public :
    virtual ~Parent() { }
};
class Child : public Parent
{
};
void main( )
{
    Parent objParent;

    Child objChild;
    cout << typeid( objParent ).name() << endl;
    cout << typeid( objChild ).name() << endl;

    Parent *p = NULL;
    p = new Parent;
    cout << typeid( *p ).name() << endl;
    p = new Child;
    cout << typeid( *p ).name() << endl;
} 

class Parent
class Child
class Parent
class Child

 typeid() 연산자는 타입 정보 객체의 레퍼런스를 리턴합니다. 함수의 원형은 const type_info& typeid(type_name); 입니다. const type_info&를 반환합니다.

 

그래서 위 예제는 아래처럼 사용할 수 있습니다.( 더 복잡?하게..)

#include <iostream>
#include <typeinfo>
using namespace std;
class Parent
{
public :
    virtual ~Parent() { }
};
class Child : public Parent
{
};
void main( )
{
    Parent objParent;

    Child objChild;
    const type_info& info1 = typeid( objParent );
    cout << info1.name() << endl;
    const type_info& info2 = typeid( objChild );
    cout << info2.name() << endl;

    Parent *p = NULL;
    p = new Parent;
    const type_info& info3 = typeid( *p );
    cout << info3.name() << endl;
    p = new Child;
    const type_info& info4 = typeid( *p );
    cout << info4.name() << endl;
}

  1. class Parent
    class Child
    class Parent
    class Child

 type_info 객체는 생성하거나 변경할 수 없습니다. 생성자가 private으로 접근할 수 없고 typeid()가 const 객체를 리턴하므로 변경할 수 없습니다. 정보를 얻는 용도로만 사용합니다.

 

type_info 클래스는 아래와 같은 멤버로 정의되어 있습니다.

 class type_info {
public:
    virtual ~type_info();
    bool operator==(const type_info& rhs) const;
    bool operator!=(const type_info& rhs) const;
    int before(const type_info& rhs) const;
    const char* name(__type_info_node* __ptype_info_node = &__type_info_root_node) const;
    const char* raw_name() const;
private:
    void *_m_data;
    char _m_d_name[1];
    ...
};

 

그래서 객체 비교도 가능합니다.

#include <iostream>
#include <typeinfo>
using namespace std;
class Parent
{
public :
    virtual ~Parent() { }
};
class Child : public Parent
{
};
class Child2 : public Parent
{
};
void main( )
{
    Parent *p1 = new Child;
    Parent *p2 = new Child2;
    Parent *p3 = new Child;


    if( typeid( *p1 ) == typeid( *p2 ) )
        cout << "같은 타입 객체" << endl;
    else
        cout << "다른 타입 객체" << endl;
    if( typeid( *p1 ) == typeid( *p3 ) )
        cout << "같은 타입 객체" << endl;
    else
        cout << "다른 타입 객체" << endl;
}

  1. 다른 타입 객체
    같은 타입 객체

 *p1과 *p2는 Child와 Child2 클래스 타입으로 서로 다릅니다. *p1과 *p3는 모두 Child 클래스 타입으로 같습니다. type_info 클래스가 제공하는 인터페이스를 사용하여 더 많은 기능을 수행할 수 있습니다.

 

RTTI는 객체들의 정보를 얻는 곳에만 사용하는 것이 좋습니다. 객체들을 비교, 구분하기 위해 RTTI를 난발하는 것은 프로그램 구조나 효율, 확장성 및 유연성 등에 좋지 않습니다. RTTI를 사용하여 객체를 비교하는 코드 대부분에 다형성을 이용하여 구현할 수 있습니다. RTTI는 객체의 간단한 정보를 얻기 위해서만 사용하세요.