Unreal5/Unreal C++

[U C++] Interface

taene_ 2024. 7. 6. 17:24

Interface의 정의

  • 객체가 반드시 구현해야 할 행동을 객체와 분리해서 만들고 행동을 하도록 지정하는데 활용되는 타입
  • 다형성의 구현, 의존성이 분리된 설계에 유용하게 활용한다.

 

언리얼 엔진에서 게임 콘텐츠를 구성하는 오브젝트의 설계 예시

  • 월드에 배치되는 모든 오브젝트(안 움직이는 오브젝트도 포함)를 Actor라 한다.
  • 이 중 움직이는 오브젝트를 Pawn이라 하는데, 길찾기 시스템을 반드시 사용하면서 움직이는 오브젝트이다.

 

Interface의 특징

  • 클래스가 반드시 구현해야 하는 기능을 지정하는데 사용한다.
  • C++은 기본적으로 다중 상속을 지원하지만, 언리얼 C++의 인터페이스를 사용해 가급적 축소된 다중 상속의 형태로 구현하는 것이 향후 유지보수에 도움된다.
  • 언리얼 C++ 인터페이스를 생성하면 두 개의 클래스를 생성한다.
    • U로 시작하는 타입 클래스( 클라스 타입 정보의 제공 )
    • I로 시작하는 인터페이스 클래스( 실질적인 설계 및 구현 )
      • 객체를 설계할 때 I 인터페이스 클래스를 사용한다.
        • U타입 클래스 정보는 런타임에서 인터페이스 구현 여부를 파악하는 용도로 쓰인다.
        • 실제로 U타입 클래스에서 작업할 일은 없다.
        • 인터페이스에 관련된 구성 및 구현은 I 인터페이스 클래스에서 진행된다.
  • C++ 인터페이스의 특징
    • 추상 타입으로만 선언할 수 있는 Java, C#과 달리 언리얼은 인터페이스에도 구현이 가능하다.
  • 언리얼 C++ 인터페이스는 추상 타입으로 강제되지 않고, 내부에 기본 함수를 구현할 수도 있다.

 

Interface의 활용

// LessonInterface.h

#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:
	virtual void DoLesson() = 0;	//abstract 추상 가상 함수(=0)를 선언하면 이 인터페이스를 상속받는 클래스는 반드시 해당 함수를 구현해 줘야한다.
};
// Student.h

#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;	
	// ILessonInterface를 상속받았으므로
	// 그의 추상 함수인 DoLesson()을 반드시 구현해야 한다.

private:

};
// MyGameInstance.cpp

#include "MyGameInstance.h"
#include "Student.h"
#include "Teacher.h"
#include "Staff.h"
#include "LessonInterface.h"

UMyGameInstance::UMyGameInstance()
{
	SchoolName = TEXT("OO대학교");
}

void UMyGameInstance::Init()
{
	Super::Init();

	TArray<UPerson*> Persons = { NewObject<UStudent>(), NewObject<UTeacher>(), NewObject<UStaff>() };
	for (const auto Person : Persons)
	{
		UE_LOG(LogTemp, Log, TEXT("구성원 이름: %s"), *Person->GetName());
	}

	for (const auto Person : Persons)
	{
		ILessonInterface* LessonInterface = Cast<ILessonInterface>(Person);
		if (LessonInterface)
		{
			UE_LOG(LogTemp, Log, TEXT("%s님은 수업에 참여할 수 있습니다."), *Person->GetName());
			LessonInterface->DoLesson();
		}
		else
		{
			UE_LOG(LogTemp, Log, TEXT("%s님은 수업에 참여할 수 없습니다."), *Person->GetName());
		}
	}
}