유지보수와 유연함, 확장성 향상을 위한 객체지향 프로그래밍 원칙(SOLID)
S(Single Responsibility) : 하나의 클래스는 하나의 책임만 가져야 함
O(Open/Closed) : 클래스 설계를 변경하지 않고 동작을 확장할 수 있어야 함
L(Liskov Subtitution) : 자식 클래스는 부모 클래스를 대체 사용할 수 있어야 함
I(Interface Segregation) : 작고 명확한 인터페이스들로 분리해 관리해야 함
D(Dependency Inversion) : 구체적인 클래스가 아닌 인터페이스에 의존해야 함
C#, JAVA부터 보완한 새로운 기능
Interface : 객체 설계의 틀을 제공하는 추상 클래스
Reflection : 런타임에서 객체의 구조를 파악하고 객체에 메타 데이터를 부여
Delegate : 프로그램에서 발생한 이벤트를 다수의 객체에 효과적으로 전달하는데 활용
성능과 유지보수를 모두 갖기 위해 언리얼은 C++에 매크로 기능을 활용하여 모던 객체 지향 언어들이 가지고 있는 기능을 사용
C++ 오브젝트 : 저수준의 빠른 처리를 위한 기능 구현에 사용
언리얼 오브젝트 : 콘텐츠 제작에 관련된 복잡한 설계 구현에 사용
언리얼 오브젝트
클래스가 언리얼 오브젝트인지 지정하기 위해 UCLASS 매크로 사용
언리얼 오브젝트 생성할 때 NewObject<class>() 사용
특징
클래스 기본 객체(CDO) : 클래스의 기본 값과 타입 정보 제공
리플렉션 : 런타임에서 클래스 정보 참조 기능
가비지 컬렉션 : 자동 메모리 관리
직렬화 : 객체 정보를 바이트 스트림으로 저장, 전송, 로드하는 기능
네트워크 리플리케이션
언리얼 헤더 툴
ProjectName_API : 다른 DLL(모듈)에서 언리얼 오브젝트 클래스를 사용할 수 있도록 하는 키워드
GENERATED_BODY : 객체지향 설계를 위해서 제공되는 여러가지 기능들을 언리얼 엔진이 자동으로 생성
언리얼 헤더 툴에 의해서 언리얼 오브젝트 기능을 제공하기 위해 컴파일 과정에서 매크로들을 참조해 genreated.h를 자동으로 생성하고 최종 빌드 됨
언리얼 오브젝트 리플렉션(프로퍼티) 시스템
https://www.unrealengine.com/ko/blog/unreal-property-system-reflection
런타임에 자기 자신을 조사하는 기능을 지원
C++은 리플렉션을 지원하지 않아 언리얼에서 Unreal Build Tool(UBT)와 Unreal Header Tool(UHT)을 사용하여 자체적으로 구축
언리얼 오브젝트에만 적용되며 옵션이므로 사용할지 안할지 선택할 수 있음
"FileName.genterated.h"를 include하고 UENUM(), UCLASS(), USTRUCT(), UFUNCTION(), UPROPERTY() 매크로를 사용하여 리플렉션으로 등록
언리얼 오브젝트를 선언할 때 항상 generated.h 파일이 가장 마지막에 include 해야 함
cpp 파일에서 언리얼 오브젝트가 선언된 헤더 include 순서가 가장 위에 있어야 함
함수 본문에 GENERATED_BODY() 매크로가 필수적
매크로 안에 메타 데이터를 지정하여 게임 컨텐츠를 제작할 때 에디터와 연동하여 여러가지 기능을 만들 수 있음
멤버를 UPROPERTY로 선언하면 언리얼에서 자동으로 초기화 및 메모리 관리(가비지 컬렉션), 선언하지 않았다면 직접 메모리를 관리해야 함
언리얼 오브젝트 계층 구조
위로 갈수록 상위 클래스
UStruct는 컴포지션으로 UField를 소유
언리얼 오브젝트 클래스는 UTypeName::StaticClass()나 Instance->GetClass()를 사용하여 UHT가 자동으로 생성한 리플렉션 정보를 보관한 객체에 접근할 수 있음
for( TFieldIterator<UProperty> PropIt(GetClass()); PropIt; ++PropIt)
{
...
}
각 유형에 플래그나 메타 데이터 등이 있어서 필요한 것만 필터링해서 얻을 수 있음
런타임에 어떤 UClass인지 알 수 있으며 형변환이 가능해짐
UPROPERTY를 사용해야 하는 경우
메모리를 GC를 통해 관리해야 하는 변수
블루프린트나 리플렉션을 통해서 참조하는 변수
// Outer를 설정하여 컴포지션 관계 설정 및 객체의 생명 주기를 Outer와 동일하게
CourseInfo = NewObject<UCourseInfo>(this);
// 객체의 생명 주기를 유지할 필요가 없기 때문에 Outer 설정 X
UStudent* Student1 = NewObject<UStudent>();
// AddUObject를 사용하여 오브젝트의 멤버 함수를 바인딩
CourseInfo->OnChanged.AddUObject(Student1, &UStudent::GetNotification);
예제를 통해 실습한 결과 Delegate 호출할 때 바인딩이 늦게 된 순서대로 호출되는 것으로 보임
언리얼 오브젝트 처리
UPROPERTY로 선언한 멤버는 자동으로 0으로 초기화됨
언리얼 오브젝트 객체의 UPROPERTY로 지정한 것만 사용자가 지정한 포맷에 맞게 I/O해줌
- Serialization, 네트워크 통신에 사용
CDO(Class Default Object)
언리얼 객체가 가진 기본 값을 보관하는 템플릿 객체
한 클래스로부터 다수의 물체를 생성할 때 같은 기본 값을 조정하는 데 사용됨
GetDefaultObject()를 통해 얻을 수 있음
엔진 초기화 이후 사용할 수 있으므로 CDO의 기본값을 변경하는 경우에 에디터를 끄고 다시 컴파일해야 함
형변환할 때 Cast를 사용하여 실패하면 nullptr을 보장해주기 때문에 안전하게 형변환 가능
리플렉션을 활용하면 접근 지시자와 무관하게 값을 설정할 수 있으므로 상황에 따라서는 필요할 수도 있음
UStudent* Student = NewObject<UStudent>();
UTeacher* Teacher = NewObject<UTeacher>();
UTeacher::StaticClass()->FindPropertyByName(TEXT("Name")); // 프로퍼티 정보를 가져올 수 있음
if (NameProp)
{
NameProp->GetValue_InContainer(Teacher, &CurrentTeacherName); // 프로퍼티의 값을 가져옴
NameProp->SetValue_InContainer(Teacher, &NewTeacherName); // 프로퍼티의 값을 변경함
}
UFunction* DoLessonFunc = Teacher->GetClass()->FindFunctionByName(TEXT("DoLesson")); // 함수에 대한 객체 얻음
if(DoLessonFunc)
{
Teacher->ProcessEvent(DoLessonFunc, nullptr); // 리플렉션을 활용한 함수 실행
}
'언리얼 > 언리얼 C++ 및 개념' 카테고리의 다른 글
언리얼 오브젝트 직렬화 (0) | 2024.07.20 |
---|---|
언리얼 가비지 컬렉션 (0) | 2024.07.18 |
언리얼 컨테이너 라이브러리 - Array, Set, Map, Struct (0) | 2024.07.12 |
언리얼 C++ 델리게이트 (0) | 2024.07.11 |
언리얼 C++ 설계 (0) | 2024.07.09 |