RTTI 란?
Run Time Type Information or Run Time Type Identification의 약자로 실행시간에 타입정보를 식별 정도로 풀이할 수 있습니다.
정확한 의미는, 실행중에 기반 클래스 타입 포인터의 실체를 밝혀내는데 목적을 두고 있습니다.
C++ 표준화의 역사와 RTTI의 등장
1991: First meeting of WG21
1994: CD1 : CD2에 내용이 없어서 CD1으로 판단하였는데 정확하지 않습니다>
1996: CD2
1997: FDIS (Final Draft International Standard)
1998: C++ Standard (C++98)
CD : Committee Draft
TR : Technical Report
WG : Working Group
WG21 : WG for C++
RTTI 는 현재 표준화 된 지원을 제공하지만, 애초부터 표준이었던 것은 아닙니다.
C와의 후방 호환성을 유지하며, C의 효율성 유지에 대한 우려때문이었습니다.
가상함수라는 대안도 있었지만 결국 정적 타입체크 와 가상함수들로는 불가능한 문제점들이 제시되었습니다.
결국 C++ 표준화 위원회는 RTTI 추가를 승인하였습니다.
그 이전에는 각각 독자적으로 RTTI 기능을 소스코드 수준에서 구현하여 제공하였는데, 그 대표적인 예가 92년에 등장한 MFC의 RTTI 입니다.
CRuntimeClass 와 몇가지 매크로를 통해서 구현하게 되어있는데 현재까지도 MFC에서 사용되고 있습니다.
MFC RTTI 에 관해서는 http://captainthomas.tistory.com/entry/MFC-RTTI-CRuntimClass 를 참고하시기 바랍니다.
RTTI 는 어째서 필요한가?
RTTI는 위에서 언급했듯 실행중에 기반 클래스 타입 포인터의 실체를 밝혀내는데 목적으로 하고 있습니다.
정확하게 다형성을 가진 객체에 대해 정확한 타입을 알아내기 위해서 나왔다고 볼 수 있습니다.
간단한 예를 들면 Base 클래스가 있고 그것을 상속받은 Child1, Child2 클래스가 존재한다고 가정했을때,
Base* m_Base = new Child1();
이렇게 할당하였을 경우 기존의 방법으로는 실행중에 m_Base 가 가르키고 있는 객체가 Child1 이라는 것을 알 수가 없습니다.
하지만 RTTI 를 사용하면 Child1 타입이라는 것을 정확하게 알 수 있게 됩니다.
이것은 하나의 단편적인 예이며 사실 가상함수를 사용하는 다형성을 통해서 굳이 런타임때 타입을 알필요가 없을지도 모릅니다.
하지만 가상함수로도 해결할 수 없는 문제점을 RTTI 를 통해서 해결 가능한 부분들이 존재합니다.
이에 관해서는 http://blog.naver.com/moodern?Redirect=Log&logNo=80005025903 를 참고하시기 바랍니다.
제약사항
위에서 다형성이란 말을 언급하였는데 , 이 다형성을 구현하기 위해서 C++ 은 가상함수를 사용하며, 이 가상함수를 위해 별도의 공간을 사용하고 있습니다. 바로 vftbl 이라는 가상함수 테이블입니다.
RTTI 정보는 vftbl 에 저장되기 때문에 가상함수가 사용된 클래스에 한해서만 정보가 유지되게 됩니다.
즉, 비다형성 클래스의 객체는 RTTI 정보를 가지지 않습니다. (프리미티브 타입들도 마찬가지입니다)
이는 RTTI를 일반적인 클래스 객체에 두게되면 C와의 하위호환성을 포기해야 되는 사태가 발생합니다.
C의 구조체와 C++의 클래스 객체는 바이너리 호환성을 지니기 때문에 C에서 객체에 액세스가 가능한데 , C++ 클래스가 멤버중 vitrual 을 가지게 되면 액세스가 불가능한 점을 볼 수가 있습니다.
RTTI 의 간단한 예
다형성과 비다형성을 가진 클래스에 대해 RTTI 정보에 대해서 쉽게 테스트 해 볼 수 있습니다.
10 | class Child1 : public Base |
16 | class Child2 : public Base |
24 | Base* Cast = new Child1(); |
25 | Base* Cast2 = new Child2(); |
26 | printf ( "%s \n" , typeid (*Cast).name() ); |
27 | printf ( "%s \n" , typeid (*Cast2).name() ); |
위와 같이 비 다형성 클래스에 대해서 선언하여 클래스 타입을 조회하면 둘다 "Class Base"로 나오게 됩니다.
정체성을 잃어버리고 자기가 누군질 모르고 있습니다.
즉 RTTI 정보를 가지지 않게 됩니다.
12 | class Child1 : public Base |
19 | class Child2 : public Base |
28 | Base* Cast = new Child1(); |
29 | Base* Cast2 = new Child2(); |
30 | printf ( "%s \n" , typeid (*Cast).name() ); |
31 | printf ( "%s \n" , typeid (*Cast2).name() ); |
이번에는 클래스 내부에 의미없는 virtual 멤버를 포함시켰습니다.
수행결과는
"Class Child1"
"Class Child2"
로 나오게 됩니다. 지가 누군지 알게 되었네요.
RTTI 정보를 가지게 되는 것을 알 수 있습니다.
C++ RTTI 에 의존하는 dynamic_cast 도 상속 관계 안에서 하나 이상의 가상함수를 가지고 있어야 하며, RTTI 기능이 활성화 되어야 사용할 수 있는 제약사항을 동일하게 가집니다.
마치며
간단하게 C++ RTTI 에 알아보기 위해서 썼기 때문에 정작 중요한 예나 비용등의 언급은 빠졌습니다.
RTTI 에 관련된 정보는 많이 있기 때문에 검색을 통해 충분히 찾을 수 있을 것으로 생각됩니다.
자세한 예와 사용에 대해서는 http://blog.naver.com/lovinghc?Redirect=Log&logNo=30013832987 를 참고하시기 바랍니다.