KoreanFoodie's Study
C++ DevNote : 타입 정보 RTTI(Runtime Type Infomation or Runtime Type Identification) 에 대하여 본문
C++ DevNote : 타입 정보 RTTI(Runtime Type Infomation or Runtime Type Identification) 에 대하여
GoldGiver 2022. 12. 27. 21:47
C++ 에 대해 공부한 것과, 개발하면서 알게 된 것들을 다룹니다
RTTI
RTTI 는 간단히 말해, 실시간 타입 정보라는 뜻이다. RTTI 라는 단어를 평소에는 잘 들어볼 일이 없다가, dynamic_cast 를 사용하기 위해 비주얼 스튜디오 옵션을 뒤적이던 중 해당 항목을 발견했다.
알다시피, C++ 는 리플렉션 기능을 제공하지 않는다. C# 에서는 리플렉션을 제공하는데, 해당 기능은 런타임에서 클래스 타입, 메소드, 프로퍼티 등의 메타 정보를 제공해 준다.
비주얼 스튜디오에서는 해당 기능을 끄고 킬 수 있게 만들어 놓았다.
간단히 말해, 해당 기능을 키게 되면 런타임에서 타입에 대한 정보를 얻을 수 있다. RTTI 는 가상 함수가 있는 클래스에 대해서만 동작하며, 이는 클래스의 타입 관련 정보가 vtable 에 같이 저장되기 때문이다. 컴파일러는 컴파일 번역 이후 이름을 실행 파일에 남길 필요가 없어 RTTI 로 정보를 가져온다.
RTTI 가 제대로 동작하기 위해선 모든 클래스에 타입과 관련된 정보를 작성해야 한다. 물론 이것을 키면 프로그램의 성능이 느려지고 용량이 비대해지는 부작용이 있다.
C++ 는 RTTI 를 지원하는 세 가지 요소를 갖고 있다.
- dynamic_cast : 기반 클래스에서 파생 클래스로의 다운 캐스팅 시 사용. 실패할 경우 nullptr 리턴
- typeid 연산자 : 객체의 타입 식별값을 리턴
- type_info : 타입에 대한 정보를 저장
dynamic_cast
dynamic_cast 의 경우 이전 글에 정리한 내용을 참고하자.
추가로 한 마디 덧붙이자면, dynamic_cast 는 참조에서도 사용이 가능하나, 참조에서는 nullptr 에 해당하는 참조값이 없다. 따라서 변환될 수 없을 경우 bad_cast 예외가 발생한다(exception class from typeinfo header file).
typeid 연산자, type_info 클래스
typeid 연산자를 사용하기 위해서는 typeinfo 헤더 파일을 include 해주면 된다.
typeid 연산자를 이용해 객체의 데이터형이 동일한지를 파악할 수 있으며, 이는 type_info 객체에 대한 참조를 리턴한다. 이를 위해 type_info 클래스는 테이터형을 비교하는 데 사용할 수 있는 '==' 와 '!=' 연산자를 갖고 있다.
#include <iostream>
#include <typeinfo>
using namespace std;
class A {
public:
virtual void foo() { cout << "A" << endl; }
};
class B : public A {
public:
virtual void foo() { cout << "B" << endl; }
};
int main(void) {
A* a = new A();
B* b = new B();
A* arr[2];
arr[0] = a;
arr[1] = b;
for (int i = 0; i < 2; ++i)
{
arr[i]->foo();
if (typeid(B) == typeid(*arr[i]))
{
B* bb = (B*)arr[i];
bb->foo();
cout << "현재 타입 : " << typeid(*arr[i]).name() << endl;
}
}
}
위 코드의 결과값은 다음과 같다 :
A
B
B
현재 타입 : 1B
1B 에서 앞에 붙은 1 은 타입명의 길이를 의미한다. 만일 nullptr 로부터 typeid 를 얻으려 한다면 bad_typeid 예외가 발생한다!
RTTI 를 사용하면 프로그램 효율을 떨어뜨릴 수 있으며, 이를 남용하는 것은 좋은 습관이 아니다. 주로 디버깅을 위해 사용하는 것이 권장되고 있다.
물론, typeid 를 활용하면 좋은 경우도 간혹 존재한다. boost::any 에서 any_cast 를 구현하기 위해 typeid 를 사용한 다음 예시 코드를 보자.
template<typename T> any_cast(const any& other) {
if(typeid(T) != other.type()) throw bad_any_cast();
//...actual cast here...
}
위에서 T 는 polymorphic 함을 확신할 수 없으므로 dynamic_cast 를 사용할 수 없다. 이 경우에서는 typeid 를 활용해야만 타입 안정성을 보장할 수 있다!
참고 : 블로그 1, 블로그 2, StackOverflow
'Tutorials > C++ : Expert' 카테고리의 다른 글
C++ DevNote : 생성자를 private 하게 만드는 이유 (feat. make_shared 대신 new 를 사용한다고?) (0) | 2023.09.14 |
---|---|
C++ DevNote : 파생 클래스에서 기반 클래스 생성자 제대로 호출하기 (0) | 2022.12.27 |
C++ DevNote : 우측값과 좌측값 완벽 정리 (glvalue, rvalue, lvalue, xrvalue, prvalue) (0) | 2022.12.26 |
C++ DevNote : const_cast 의 개념과 주의점 (0) | 2022.12.26 |