6. CDO / UObject

JUSTICE_DER·2023년 7월 21일
0

🌵UNREAL

목록 보기
37/42

Unreal Engine 관련 자료들을 검색하다보면
항상 CDO라는 단어가 껴있었다..

특히 리플렉션의 경우에도 종종 보였는데..
이번에 ConstructHelper관련된 자료를 찾아보다가
CDO를 알아야만 하겠다는 생각이 들어서 공부해본다.

아래의 글들을 참고하였다.

1. CDO란 무엇인가

CDO는 UObject가 제공하는 기능들 중에 하나이다.
따라서 UObject부터 제대로 알아야 해당 기능을 설명할 수 있다.

UObject가 되면 위의 기능들을 모두 사용할 수 있다.
(그렇게 언리얼 엔진이 기능을 제공한다)

1-1. UObject

아래의 글을 참고하였다.

UObject란

  • prefix U가 붙은 오브젝트
  • NewObject()로 생성해야만 하는 객체
    를 의미한다.

언리얼에서는 Native CPP 객체를 사용할 수도 있고,

  • prefix F가 붙은 오브젝트
  • new T()를 사용하여 생성하는 객체
    를 의미하게 된다.

언리얼 오브젝트는 CPP표준이 아니기 때문에,
일반적인 방법으로는 만들 수 없다.
생성에 UHT의 도움을 받아야만 한다.

언리얼 오브젝트처럼 보이도록 1)형식에 맞춰서 CPP파일을 생성한다면,
바로 컴파일하는 것이 아니라 2)UHT가 해당 CPP파일을 분석한다.
형식이 언리얼 UObject와 맞는지 분석한 후 맞다면,
UHT는 3)메타정보를 담은 소스코드를 프로젝트의 intermediate폴더에 생성한다.

이 작업이 끝나야 비로소 컴파일이 진행되게 된다.
해당 파일은 UObject로 보겠다는 것이다.

A. UObject의 형식

UObject로 인식시키기 위한 필수 형식은 아래와 같다.

위의 5가지 요소가 포함되어야만 UObject형식을 만족하고,
UHT가 5가지 요소가 포함되었는지 검사하고
정답을 다 맞아야만 intermediate폴더에 해당 클래스의 메타데이터를 넣어
UObject로 보고 컴파일하겠다는 것이다.

3 - 접두사는 U / A / S가 존재한다.
엑터기반이면 A이고, 나머지는 일반적으로 U를 붙인다.
(S는 UI담당하는 슬레이트? 용이라고 함)

[리플렉션]
리플렉션을 위한 generated.h / UCLASS / GENERATED_BODY가 있으니,
리플렉션을 할 수 있다고 UHT가 보도록 마킹을 해두는 것이고,
내부에서 UPROPERTY를 하면 실제로 리플렉션이 동작할 것이다.

UObject로 인식시키기 위한 부가 형식은 아래와 같다.

  • 1 - 모듈이름_API
    • 이렇게 선언해야만 다른 모듈에서 현재 모듈 내
      해당 클레스에 접근할 수 있게 된다.
  • 2 - 생성자
    • 언리얼 오브젝트의 기본값을 지정하는데 사용
    • 클래스 기본 객체인 CDO를 생성할 때, 해당 생성자 코드가 1번 실행됨
  • 3 - UPROPERTY()
    • 설명했듯이 해당 매크로를 사용하면 리플렉션의 대상이되고,
      언리얼엔진의 관리를 받게 된다. (GC)
  • 4 - UFUNCTION()
    • 해당 매크로를 사용하면 함수를 블루프린트에서 연동되게 할 수 있다.
    • 추가로, delegate / 리플리케이션? 과 같은 함수를 사용가능

1-2. CDO (Class Default Object)

UObejct에 대해서 알아보았으니,
UnrealEngine이 UObejct에게 제공하는 CDO라는 기능을 알아본다.

아래의 글을 참고하였다.

모두 요약했는데 내용이 저장이 안되어 사라졌다...
간단히 다시 적어본다.

해당 사진만 이해하면 CDO의 생성과정에 대해서 알 수 있다.

우선 가장 먼저 시작하는 부분은 UObject클래스의 선언이다.
이전에 봤듯이, UObject는 Native CPP로 컴파일해야만 하고,
해당 형식을 맞춰서 컴파일하고, UHT가 분석하여
형식이 맞는지 확인을 거쳐야만, UObject로서 사용될 수 있다고 했다.

UObject로 형식을 인정받은 클래스는
Intermediate폴더에 UObject로서 메타정보를 담을 수 있게 되고,
해당 정보는 UClass라는 특수 클래스를 통해 우선 선언만 하게 된다.
(메타정보는 멤버변수/함수, 클래스 계층구조 정보)
이를 통해 런타임과정에서도 엔진에서 확인할 수 있는 Reflection을 지원할 수 있다.

이처럼, 컴파일 단계에선 UHT가 UObject 각각의 UClass Class를 선언하게 된다.

런타임 초기 단계에선 UObject마다 UClass의 인스턴스를 실제로 생성한다.
해당 인스턴스에 메타 데이터를 담게 되고,
해당 UClass 인스턴스를 바탕으로
추가로 UObject인스턴스를 생성하게 된다

해당 UObject인스턴스를 CDO라고 부른다.
CDO를 바탕으로, 런타임중 월드에 생성될 UObject들을 초기화한다.

따라서 기본 객체를 만들어두고 복사하는 방식으로 구현하는 방식을 사용한다.

언리얼에서 클래스의 생성자는 CDO를 초기화하는데 사용된다.

즉, 런타임 초기시에 모든 UObject의 CDO가 생성되고,
생성자는 이때에만 호출되게 된다 (런타임초기 딱 1번)
이게 과연 맞는 말일까..?
(따라서 게임플레이 중에 초기화할 함수는 Init이나 BeginPlay를 사용한다고 함)

결론
UClass

1-3. GetDefaultObject

https://docs.unrealengine.com/5.1/en-US/API/Runtime/CoreUObject/UObject/UClass/GetDefaultObject/1/

클래스의 기본 속성값을 빠르게 파악하기 위한 함수이다.

// UClass에 대한 포인터를 얻은 후 CDO를 얻어오는 예제
UClass* MyClass = ...; // 어떤 클래스에 대한 포인터를 얻음
if (MyClass)
{
    UObject* DefaultObject = MyClass->GetDefaultObject();
    if (DefaultObject)
    {
        // CDO를 통해 기본 속성 값을 확인
        int32 MyDefaultPropertyValue = DefaultObject->MySpeed; 
  // MySpeed : 해당 클래스의 속성 이름
    }
}

https://cafe.naver.com/unrealenginekr?iframe_url_utf8=%2FArticleRead.nhn%253Fclubid%3D27085438%2526articleid%3D14085

CDO를 만드는 생성자에서만 사용할 수 있는
ConstructorHelper

profile
Time Waits for No One

0개의 댓글