0. 강의 내용 요약
언리얼 C++ 인터페이스
1. 클래스가 반드시 구현해야 하는 기능을 지정하는데 사용함.
2. C++ 은 기본적으로 다중상속을 지원하지만, 언리얼 C++ 의 인터페이스를 사용해 가급적 축소된 다중상속의 형태로 구현하는 것이 향후 유지보수에 도움된다.
3. 언리얼 C++ 인터페이스는 두 개의 클래스를 생성한다.
4. 언리얼 C++ 인터페이스는 추상 타입으로 강제되지 않고, 내부에 기본 함수를 구현할 수 있다.
언리얼 C++ 인터페이스를 사용하면, 클래스가 수행해야 할 의무를 명시적으로 지정할 수 있어 좋은 객체 설계를 만드는데 도움을 줄 수 있다.
1. 실습 코드
1.1 MyGameInstance
더보기
1. 헤더파일
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "MyGameInstance.generated.h"
/**
*
*/
UCLASS()
class UNREALINTERFACE_API UMyGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
UMyGameInstance();
virtual void Init() override;
private:
UPROPERTY() // 언리얼 엔진이 관리할 수 있도록 매크로 지정
FString SchoolName; // 이제 언리얼 엔진이 파아갛고 관리할 수 있음, 리플렉션 시스템을 사용해서 이 정보를 런타임이든 컴파일 타임이든 언제든지 가져올 수 있게됨
// 기본값을 주고 싶다면 생성자에 기본값을 지정해주면 됨
};
2. cpp 파일
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyGameInstance.h" // 이 헤더는 가장 위에 있어야함.
#include "Student.h"
#include "Teacher.h"
#include "Staff.h"
UMyGameInstance::UMyGameInstance()
{
// CDO 의 생성 시점은 대체 언제인가?
// 클래스 정보와 CDO 엔진 초기화 과정에서 생성되므로 게임 개발에서 안전하게 사용 가능
// 생성자 코드에서 Class Default Object 의 기본값을 변경하는 경우에는 에디터를 끄고 컴파일해서 다시 실행해주기~
SchoolName = TEXT("기본학교"); // 기본값 지정
}
void UMyGameInstance::Init() {
Super::Init();
UE_LOG(LogTemp, Log, TEXT("========================"));
// 부모 객체 포인터의 어레이
TArray<UPerson*> Persons = { NewObject<UStudent>(), NewObject<UTeacher>(), NewObject<UStaff>() };
for (const auto Person : Persons)
{
UE_LOG(LogTemp, Log, TEXT("구성원 이름 : %s"), *Person->GetName());
}
UE_LOG(LogTemp, Log, TEXT("========================"));
for (const auto Person : Persons)
{
// Cast 연산자는 형변환 실패하면 null 을 반환함
// 즉, 이를 이용해서 어떤 클래스가 특정 클래스 또는 인터페이스를 상속받는지 확인할 수 있음
ILessonInterface* LessonInterface = Cast<ILessonInterface>(Person);
if (LessonInterface)
{
// 여기에 도달했다는 것은 ILessonInterface 를 상속받았음을 의미
UE_LOG(LogTemp, Log, TEXT("%s님은 수업에 참여할 수 있습니다."), *Person->GetName());
LessonInterface->DoLesson(); // ILessonInterface 를 상속받은 애만 DoLesson 함수 호출
}
else
{
UE_LOG(LogTemp, Log, TEXT("%s님은 수업에 참여할 수 없습니다."), *Person->GetName());
}
}
UE_LOG(LogTemp, Log, TEXT("========================"));
}
1.2 Person
더보기
1. 헤더파일
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "Person.generated.h"
/**
*
*/
UCLASS()
class UNREALINTERFACE_API UPerson : public UObject
{
GENERATED_BODY()
public:
UPerson();
// forchinline 을 통해서 최대한 인라인이 되도록 선언..
FORCEINLINE FString& GetName() { return Name; }
FORCEINLINE void SetName(const FString& InName) { Name = InName; }
protected:
UPROPERTY() // 언리얼이 관리할 수 있게 속성으로 발전시키기위해 매크로 추가
FString Name;
};
2. cpp 파일
// Fill out your copyright notice in the Description page of Project Settings.
#include "Person.h"
UPerson::UPerson()
{
Name = TEXT("홍길동");
}
1.3 Student
더보기
1. 헤더파일
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Person.h"
#include "LessonInterface.h"
#include "Student.generated.h"
/**
*
*/
UCLASS()
class UNREALINTERFACE_API UStudent : public UPerson, public ILessonInterface
{
GENERATED_BODY()
public:
UStudent();
// 인터페이스 상속했으니까 해당 인터페이스의 가상 함수를 무조건 구현해야함
virtual void DoLesson() override;
};
2. cpp 파일
// Fill out your copyright notice in the Description page of Project Settings.
#include "Student.h"
UStudent::UStudent()
{
Name = TEXT("이학생");
}
void UStudent::DoLesson()
{
// LessonInterface 의 DoLesson 함수는 Super 로 가져올 수 없음
// 얘의 Supter 는 Person 이기 때문..
ILessonInterface::DoLesson(); // 어쩔 수 없이 직접 ILessonInterface 써줘야함
UE_LOG(LogTemp, Log, TEXT("%s님은 공부합니다."), *Name);
}
1.4 Teacher
더보기
1. 헤더 파일
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Person.h"
#include "LessonInterface.h"
#include "Teacher.generated.h"
/**
*
*/
UCLASS()
class UNREALINTERFACE_API UTeacher : public UPerson, public ILessonInterface
{
GENERATED_BODY()
public:
UTeacher();
virtual void DoLesson() override;
};
2. cpp 파일
// Fill out your copyright notice in the Description page of Project Settings.
#include "Teacher.h"
UTeacher::UTeacher()
{
Name = TEXT("이선생");
}
void UTeacher::DoLesson()
{
ILessonInterface::DoLesson(); // 어쩔 수 없이 직접 ILessonInterface 써줘야함
UE_LOG(LogTemp, Log, TEXT("%s님은 가르칩니다."), *Name);
}
1.5 Staff
더보기
1. 헤더 파일
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Person.h"
#include "Staff.generated.h"
/**
*
*/
UCLASS()
class UNREALINTERFACE_API UStaff : public UPerson
{
GENERATED_BODY()
public:
UStaff();
};
2. cpp 파일
#include "Staff.h"
// Fill out your copyright notice in the Description page of Project Settings.
#include "Staff.h"
UStaff::UStaff()
{
Name = TEXT("이직원");
}
1.6 LessonInterface
더보기
1. 헤더 파일
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "LessonInterface.generated.h"
// 아래는 타입 정보를 관리하기 위해 언리얼 엔진이 직접 생성한 클래스 여기서 딱히 뭔가 할 필요 없음
// This class does not need to be modified.
UINTERFACE(MinimalAPI) // 인터페이스에 관련된 정보를 기록하기 위한 매크로
class ULessonInterface : public UInterface
{
GENERATED_BODY()
};
/**
* 아래 클래스를 이제 수정해야함.
*
*/
class UNREALINTERFACE_API ILessonInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
// abstract 가상 함수를 선언하게 되면
// 이 인터페이스를 상속하는 모든 클래스들은 반드시 DoLesson 함수를 구현해야함
// 즉, 특정 클래스에게 구현을 강제할 수 잇음
// 만약 virtual void DoLesson() = 0; 처럼 추상클래스 형태가 아니라 구현을 해놨다면
// 해당 인터페이스를 상속받는 클래스에게 DoLesson 구현을 강제할 수 없음
virtual void DoLesson()
{
UE_LOG(LogTemp, Log, TEXT("수업에 입장합니다."));
}
};
2. cpp 파일
// Fill out your copyright notice in the Description page of Project Settings.
#include "LessonInterface.h"
// Add default functionality here for any ILessonInterface functions that are not pure virtual.