C++ 표준 RTTI(Runtime Type Information)은 기본적으로 두 가지를 제공합니다.
typeid : 타입 정보를 런타임에 가져오기
dynamic_cast : 다형성을 이용해 안전하게 캐스팅하기
이 정보는 컴파일러가 클래스마다 vtable 옆에 RTTI 블록을 추가해서 유지합니다. 예를 들어, dynamic_cast는 RTTI 정보를 참조해 다운캐스팅이 안전한지 확인합니다. 즉, C++ RTTI는 클래스의 타입 안전성(type safety)만 보장하는 최소한의 기능입니다.
장점으로는 C++ 표준이므로 특별한 준비 없이 사용할 수 있습니다.
단점은 실행 성능이 상대적으로 느리고, 크로스플랫폼/멀티플랫폼 프로젝트에서 구현 차이 때문에 이식성 문제가 발생할 수 있습니다.
위와 같은 이유로 언리얼 엔진은 성능과 확장성 때문에 C++ RTTI를 끄고 빌드됩니다. 대신 리플렉션(reflection) 시스템을 자체적으로 구현했는데, 이걸 위해 UCLASS(), UFUNCTION(), UPROPERTY() 같은 매크로를 사용합니다.
- C++ RTTI는 단순히 타입 확인과 다운캐스팅만 제공하기 때문에, 게임 엔진에서 필요한 직렬화, 네트워크 전송, 에디터 노출 같은 기능을 지원하지 못합니다.
- 대규모 오브젝트가 얽히는 게임에서는 dynamic_cast 기반 RTTI가 상대적으로 느리고, 최적화 여지가 부족합니다.
- 그래서 언리얼은 UClass, Cast<>, IsA() 같은 자체적인 리플렉션과 캐스팅 시스템을 만들어 사용합니다.
RTTI를 On/Off 할 수 있는 옵션은 *.build.cs에서 조정할 수 있고, 해당 클래스의 기반 클래스인 ModuleRules에서 정의된 것을 확인할 수 있습니다. (기본값 = off)

RTTI가 실제로 꺼져 있는지는 아래 소스코드로 확인할 수 있습니다.
#if defined(_CPPRTTI) // MSVC
UE_LOG(LogTemp, Warning, TEXT("C++ RTTI is ENABLED (_CPPRTTI defined)"));
#else
UE_LOG(LogTemp, Warning, TEXT("C++ RTTI is DISABLED (_CPPRTTI not defined)"));
#endif

그렇다면 기존 다형성 기능들은 어떻게 대체되어 있을까요?
- UCLASS(), USTRUCT(), UENUM() 매크로를 쓰면 UnrealHeaderTool(UHT)이 메타데이터 테이블을 생성.
- 모든 UObject는 UClass라는 메타 오브젝트를 가지고 있으며, 이를 통해 타입을 확인하고 캐스팅을 수행.
또한 dynamic_cast 같은 도구들을 대체하기 위한 기능들이 언리얼에서 추가로 제공됩니다.
- Cast<>() → 언리얼 전용 dynamic_cast 대체품. RTTI가 아닌 UClass 비교를 이용.
- IsA() → 객체가 특정 클래스이거나 그 파생 클래스인지 확인.
AActor* Actor = GetWorld()->SpawnActor<AActor>();
if (Actor->IsA(AMyCharacter::StaticClass()))
{
AMyCharacter* MyChar = Cast<AMyCharacter>(Actor);
}
이를 통해 얻을 수 있는 장단점은 다음과 같습니다.
장점:
- 크로스플랫폼에서 일관성 있음 (엔진이 직접 관리).
- 리플렉션과 연계되어 블루프린트, 에디터, 직렬화, 네트워크 복제 등 엔진 기능과 통합.
- 속도가 일반 RTTI보다 빠른 경우가 많음 (간단한 포인터 비교).
단점:
- UObject 기반이 아닌 순수 C++ 클래스에는 적용 불가.
- 매크로/UHT 의존성 때문에 일반 C++보다 사용이 불편할 수 있음.
이 매크로들이 하는 일은 단순한 "전처리기 치환"이 아니라, 언리얼 헤더 툴(UHT, Unreal Header Tool)이 이 정보를 읽어서 리플렉션 메타데이터를 생성하는 것입니다.
UCLASS() : 클래스가 언리얼 리플렉션 시스템에 등록되도록 함 → UClass 객체가 생성됨
UFUNCTION() : 함수가 리플렉션 시스템에 등록 → 블루프린트/네트워크/RPC 등에 노출 가능
UPROPERTY() : 멤버 변수가 에디터, 블루프린트, 직렬화 등에 반영됨
UCLASS()
class MYGAME_API AMyActor : public AActor
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category="Test")
void DoSomething();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Test")
int32 Value;
};
실제로는 다음 과정을 거칩니다.
1.컴파일 타임
- UnrealHeaderTool(UHT)이 소스를 파싱합니다.
- UCLASS, UPROPERTY, UFUNCTION 등을 읽어 .generated.h 파일을 생성합니다.
- 클래스의 메타데이터(속성, 함수, 부모 클래스 정보 등)가 C++ 코드로 자동 생성됩니다.
2.런타임
- 빌드된 코드 안에서 UClass 객체가 생성 및 전역 테이블에 등록됩니다.
- 이를 통해 에디터, 블루프린트, GC, 네트워킹, 직렬화에서 이 클래스를 인식할 수 있습니다.
| 구분 | C++ RTTI | UE5 RTTI |
|---|---|---|
| 사용법 | dynamic_cast, typeid | Cast<>, IsA(), GetClass() |
| 기반 | 컴파일러 vtable + RTTI 데이터 | UClass 메타데이터 (Reflection) |
| 적용 범위 | 모든 polymorphic 클래스 | UObject 기반 클래스만 |
| 성능 | 비교적 느릴 수 있음 | 더 가볍고 빠름 (주로 포인터 비교) |
| 이식성 | 플랫폼마다 차이 가능 | 엔진 레벨에서 동일 동작 보장 |
| 확장성 | 타입 정보만 제공 | 에디터, 블루프린트, 직렬화, 네트워크 등과 통합 |
정리하자면, UE5는 표준 C++ RTTI를 거의 쓰지 않고, UObject 기반의 리플렉션 시스템을 RTTI처럼 활용합니다. 즉, RTTI를 대체 + 확장한 개념이라고 보면 됩니다.