[UE5/C++] C++ RTTI와 언리얼 리플렉션 시스템

개발자 김선호·2025년 9월 1일

CPP

목록 보기
7/14

C++ RTTI

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

그렇다면 기존 다형성 기능들은 어떻게 대체되어 있을까요?

  1. UCLASS(), USTRUCT(), UENUM() 매크로를 쓰면 UnrealHeaderTool(UHT)이 메타데이터 테이블을 생성.
  2. 모든 UObject는 UClass라는 메타 오브젝트를 가지고 있으며, 이를 통해 타입을 확인하고 캐스팅을 수행.

또한 dynamic_cast 같은 도구들을 대체하기 위한 기능들이 언리얼에서 추가로 제공됩니다.

  1. Cast<>() → 언리얼 전용 dynamic_cast 대체품. RTTI가 아닌 UClass 비교를 이용.
  2. 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++ RTTIUE5 RTTI
사용법dynamic_cast, typeidCast<>, IsA(), GetClass()
기반컴파일러 vtable + RTTI 데이터UClass 메타데이터 (Reflection)
적용 범위모든 polymorphic 클래스UObject 기반 클래스만
성능비교적 느릴 수 있음더 가볍고 빠름 (주로 포인터 비교)
이식성플랫폼마다 차이 가능엔진 레벨에서 동일 동작 보장
확장성타입 정보만 제공에디터, 블루프린트, 직렬화, 네트워크 등과 통합

정리하자면, UE5는 표준 C++ RTTI를 거의 쓰지 않고, UObject 기반의 리플렉션 시스템을 RTTI처럼 활용합니다. 즉, RTTI를 대체 + 확장한 개념이라고 보면 됩니다.

profile
프로젝트 진행 과정을 주로 업로드합니다

0개의 댓글