UObject 클래스는 모든 언리얼 객체의 최상위 부모 클래스이다. 언리얼 엔진의 모든 클래스는 UObject 를 기반으로 상속받아 가비지 컬렉션, 리플렉션, 직렬화 등 다양한 기능을 사용할 수 있다.
C++는 기본적으로 가비지 컬렉션이 없기 때문에, 개발자가 new로 메모리를 할당하고 delete로 직접 해제해야 하며, 이 과정에서 메모리 누수가 발생할 수 있다. 반면, 언리얼 엔진은 UObject를 기반으로 한 클래스에 대해 자체적인 가비지 컬렉션 시스템을 제공하여, 메모리를 자동으로 관리해주는 편리한 장점이 있다.
| 항목 | C++ 기본 | 언리얼 엔진 (UObject 기반) |
|---|---|---|
| 가비지 컬렉션 | ❌ 없음 (수동 관리) | ✅ 있음 (자동 관리) |
| 메모리 해제 | delete 직접 호출 | GC가 자동으로 해제 |
| 순환 참조 문제 | 있음 (shared_ptr 사용 시) | 있음 (주의 필요) |
| 추적 기준 | 없음 | UPROPERTY()로 명시된 참조 |
| 객체 생성 | new, malloc 등 | NewObject<T>(), SpawnActor<T>() 등 |
UObject 클래스는 리플렉션 기능도 제공하는데 이 시스템 덕분에 런타임에 클래스, 변수, 함수 정보에 대해 접근하여 조회 및 수정 등이 가능하다.
언리얼은 UEHeaderTool이라는 전처리기를 사용해 컴파일 전에 헤더 파일을 스캔하는데 이 때, 특수 매크로를 찾아내어 클래스, 변수, 함수에 대한 메타 데이터를 생성한다. 후에 런타임 단계에서 전처리 과정에서 생성된 메타데이터를 통해 어떤 클래스의 어떤 인스턴스든 그 구조에 접근하고 조작이 가능하다.
이 과정에서 사용되는 특수 매크로는 다음과 같다.
UCLASS()UPROPERTY()UFUNCTION()각자 이름에 맞게 클래스, 변수, 함수를 리플렉션에 등록하는 매크로들이다.
UCLASS()
class UMyObject : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 Health;
UFUNCTION(BlueprintCallable)
void TakeDamage(int32 Amount);
};
UObject 를 기반으로 클래스를 생성하였을 때 헤더파일에서 위와 같이 지정을 해주면, Health 는 UPROPERTY 매크로에서 설정한 에디터, 블루프린트에서 노출, 수정이 가능하며, TakeDamage 함수는 UFUNCTION 매크로에서 설정하였듯이 블루프린트에서 호출이 가능하다.
UPROPERTY() 매크로의 속성 지정 옵션(Specifier)
Specifier 설명 EditAnywhere 에디터에서 어디서든 수정 가능 EditDefaultsOnly 클래스 디폴트에서만 수정 가능 (인스턴스에서는 불가) EditInstanceOnly 인스턴스에서만 수정 가능 (디폴트에서는 불가) VisibleAnywhere 에디터에서 읽기 전용으로 표시 BlueprintReadOnly 블루프린트에서 읽기만 가능 BlueprintReadWrite 블루프린트에서 읽기/쓰기 가능 Transient 저장되지 않음 (세이브/로드 제외) Replicated 네트워크 복제 대상 SaveGame 저장 시스템에 포함됨 Category="Stats" 에디터에서 속성 그룹 지정
UFUNCTION() 매크로의 속성 지정 옵션(Specifier)
Specifier 설명 BlueprintCallable 블루프린트에서 호출 가능 BlueprintPure 블루프린트에서 호출 가능 (실행 핀 없는 퓨어 함수) Exec 콘솔 명령어로 호출 가능 Server 서버에서 실행되는 RPC 함수 지정 Client 클라이언트에서 실행되는 RPC 함수 지정 NetMulticast 모든 클라이언트에 브로드캐스트되는 RPC 함수 지정 Reliable 네트워크 호출이 반드시 도달해야 함 (신뢰성 보장) Unreliable 네트워크 호출이 도달하지 않아도 됨 (성능 우선) Category="Combat" 블루프린트 노드에서 함수가 속할 카테고리 지정
그 외의 타입, 이름, 속성 등 메타데이터에 접근하는 기능의 정보 관련 함수들
GetClass(): 오브젝트의 UClass*를 반환. 이를 통해 런타임에 클래스의 모든 정보를 얻을 수 있음
GetName(): 오브젝트의 FString 형식 이름을 반환
GetFName(): 오브젝트의 FName 형식 이름을 반환 (FString 보다 빠름)
GetFullName(): Outer를 포함한 전체 경로 이름을 반환 ex) PackageName.OuterName.ObjectName
GetOuter(): 이 오브젝트를 포함하는 외부 UObject*를 반환
GetWorld(): 해당 오브젝트가 속한 UWorld*를 반환. 액터나 컴포넌트처럼 월드에 존재하는 오브젝트일 경우 유효한 값을 반환하며, 게임플레이 로직에 필수적
IsA<T>(): 이 오브젝트가 특정 클래스 T 이거나 T를 상속받은 클래스인지 런타임에 안전하게 확인하는 함수
직렬화는 객체의 데이터를 파일, 메모리, 네트워크 등으로 저장하거나 전송할 수 있도록 변환하는 과정
언리얼 엔진에서 UObject 기반 클래스는 리플렉션 시스템과 통합된 직렬화 기능을 제공하며, UPROPERTY() 매크로가 붙은 변수들은 자동으로 직렬화 대상에 포함된다.
이 덕분에 에디터 저장, 세이브 시스템, 네트워크 통신, 복제 등 다양한 시스템에서 객체 상태를 자동으로 저장하고 복원할 수 있다.
다만, 예외적으로 저장과 네트워크는 별개의 직렬화를 사용하며, 수동 직렬화가 필요한 경우 Serialize(FArchive& Ar) 함수를 오버라이드해서 직접 직렬화 로직을 구현할 수 있다.
직렬화: 객체를 저장 가능한 형태로 변환
↑ ↓
역직렬화: 저장된 데이터를 객체로 변환