이번 글에서는 C++의 RTTI(Runtime Type Information, 런타임 타입 정보)에 대해 알아보겠습니다.
RTTI란 무엇인가?
RTTI는 프로그램이 실행 중(runtime)일 때 객체의 실제 자료형(data type)에 대한 정보를 노출해 주는 메커니즘입니다. 이를 활용하면 컴파일 시점이 아닌 실행 시점에 객체의 정확한 타입을 판별할 수 있습니다.
다만 중요한 조건이 있습니다. RTTI 기능은 해당 클래스에 최소 하나 이상의 가상 함수(virtual function)가 존재할 때만 사용할 수 있습니다. 즉, 다형성(polymorphism)을 갖춘 클래스여야 한다는 의미입니다.
가상 함수가 없으면 어떻게 될까?
다음 예제 코드는 가상 함수가 없는 상태에서 dynamic_cast를 사용하는 경우입니다. 이 코드는 컴파일되지 않고 다음과 같은 오류를 발생시킵니다.
“cannot dynamic_cast base_ptr (of type Base*) to type 'class Derived*' (Source type is not polymorphic)”
오류 메시지 그대로, 소스 타입이 다형적(polymorphic)이지 않기 때문에 변환이 불가능하다는 뜻입니다. 클래스에 가상 함수가 없으면 vtable(가상 함수 테이블)이 생성되지 않아 런타임에 실제 객체 타입을 식별할 수 없기 때문입니다.
예제 코드 1 — 실패하는 경우
#include<iostream>
using namespace std;
class Base { };
class Derived : public Base { };
int main() {
Base *base_ptr = new Derived;
Derived *derived_ptr = dynamic_cast<Derived*>(base_ptr);
if(derived_ptr != NULL)
cout<<"It is working";
else
cout<<"cannot cast Base* to Derived*";
return 0;
}위 코드는 Base 클래스에 가상 함수가 없으므로 컴파일 오류가 발생합니다.
예제 코드 2 — 가상 함수 추가 후 성공
이번에는 Base 클래스에 가상 함수를 하나 추가해 보겠습니다. 그러면 RTTI가 활성화되어 dynamic_cast가 정상적으로 동작합니다.
#include<iostream>
using namespace std;
class Base {
public:
virtual void function() {
// 빈 함수
}
};
class Derived : public Base { };
int main() {
Base *base_ptr = new Derived;
Derived *derived_ptr = dynamic_cast<Derived*>(base_ptr);
if(derived_ptr != NULL)
cout<<"It is working";
else
cout<<"cannot cast Base* to Derived*";
return 0;
}실행 결과
It is working
정리
- RTTI는 실행 시점에 객체의 실제 타입 정보를 제공하는 C++의 메커니즘입니다.
dynamic_cast와typeid같은 연산자가 RTTI를 활용하는 대표적인 예입니다.- RTTI가 동작하려면 클래스에 최소 하나의 가상 함수가 있어야 하며, 이는 곧 다형적 타입이어야 함을 의미합니다.