개요
이번 강의에서는 Unreal Engine의 델리게이트(Delegate)를 사용하여 클래스 간의 느슨한 결합(Loose Coupling)을 구현하는 방법을 학습합니다. 발행-구독(Publish-Subscribe) 디자인 패턴을 통해 학사 정보 시스템과 학생 간의 알림 기능을 구현하면서 델리게이트의 실용적인 활용법을 익힙니다.
학습 목표
- 느슨한 결합의 장점과 델리게이트의 역할 이해
- 발행-구독 디자인 패턴의 개념과 구현 방법 학습
- Unreal 델리게이트의 다양한 종류와 선언 방법 습득
- 델리게이트를 활용한 이벤트 기반 시스템 구축
느슨한 결합이란 ?
강한 결합 (Tight Coupling)
: 클래스들이 서로 직접 의존하는 관계
// ❌ 강한 결합 - Person이 Card에 직접 의존
class UPerson
{
private:
TObjectPtr<UCard> Card; // Card 클래스에 강하게 결합
};
문제점
- 카드 시스템이 핸드폰 인증으로 변경되면 ?
- UPerson과 모든 자식 클래스를 수정해야 함
- 유지보수가 어려움
느슨한 결합 (Loose Coupling)
: 추상화를 통한 간접 의존
// ✅ 느슨한 결합 - 인터페이스를 통한 추상화
class ICheckIn
{
virtual void CheckIn() = 0;
};
class UCard : public ICheckIn
{
virtual void CheckIn() override { /* 카드로 체크인 */ }
};
class UPhone : public ICheckIn
{
virtual void CheckIn() override { /* 핸드폰으로 체크인 */ }
};
class UPerson
{
private:
TObjectPtr<ICheckIn> CheckInDevice; // 인터페이스에 의존
};
장점
- 구현이 변경되어도 UPerson 코드는 그대로
- 새로운 체크인 방식 추가 용이
- 테스트와 유지보수 간편
델리게이트 선언 방법
델리게이트 유형

선언 예시
// 인자 없음, 반환값 없음
DECLARE_DELEGATE(FSimpleDelegate)
// 인자 1개 (FString), 반환값 없음
DECLARE_DELEGATE_OneParam(FStringDelegate, const FString&)
// 인자 2개, 반환값 없음 (멀티캐스트)
DECLARE_MULTICAST_DELEGATE_TwoParams(
FOnCourseInfoChanged,
const FString&, // 주체
const FString& // 내용
)
// 인자 3개, 반환값 있음 (float)
DECLARE_DELEGATE_RetVal_ThreeParams(
float, // 반환값
FCalculateDelegate,
float, // 파라미터 1
float, // 파라미터 2
float // 파라미터 3
)
CourseInfo.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "CourseInfo.generated.h"
// 델리게이트 선언 (클래스 외부, UCLASS 위)
DECLARE_MULTICAST_DELEGATE_TwoParams(
FOnCourseInfoChangedSignature, // 델리게이트 타입 이름
const FString&, // 첫 번째 파라미터: 주체
const FString& // 두 번째 파라미터: 내용
);
UCLASS()
class UNREALDELEGATE_API UCourseInfo : public UObject
{
GENERATED_BODY()
public:
/** 생성자입니다. */
UCourseInfo();
/** 학사 정보 변경 델리게이트입니다. */
FOnCourseInfoChangedSignature OnCourseInfoChanged;
/** 학사 정보를 변경하는 함수입니다. */
void ChangeCourseInfo(const FString& SchoolName, const FString& NewInfo);
private:
/** 학사 정보 내용 변수입니다. */
FString Contents;
};
CourseInfo.cpp
#include "CourseInfo.h"
UCourseInfo::UCourseInfo()
{
// 기본 학사 정보 설정
Contents = TEXT("기존 학사 정보");
}
void UCourseInfo::ChangeCourseInfo(const FString& SchoolName, const FString& NewInfo)
{
// 학사 정보 변경
Contents = NewInfo;
// 알림 발송 로그
UE_LOG(LogTemp, Log, TEXT("[CourseInfo] 학사 정보가 변경되어 알림을 발송합니다."));
// 구독자들에게 브로드캐스트
OnCourseInfoChanged.Broadcast(SchoolName, NewInfo);
}
Student.h
#pragma once
#include "CoreMinimal.h"
#include "Person.h"
#include "Student.generated.h"
UCLASS()
class UNREALDELEGATE_API UStudent : public UPerson
{
GENERATED_BODY()
public:
/** 생성자입니다. */
UStudent();
/** 알림을 받는 함수입니다. */
void OnNotification(const FString& SchoolName, const FString& NewCourseInfo);
};
Student.cpp
#include "Student.h"
UStudent::UStudent()
{
Name = TEXT("이학생");
}
void UStudent::OnNotification(const FString& SchoolName, const FString& NewCourseInfo)
{
// 알림 수신 로그
UE_LOG(LogTemp, Log, TEXT("[Student] %s님이 알림을 받음 - 학교: %s, 내용: %s"),
*Name,
*SchoolName,
*NewCourseInfo);
}
MyGameInstance.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "MyGameInstance.generated.h"
// 전방 선언
class UCourseInfo;
UCLASS()
class UNREALDELEGATE_API UMyGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
virtual void Init() override;
private:
/** 학사 정보 변수입니다. */
UPROPERTY()
TObjectPtr<UCourseInfo> CourseInfo;
};
MyGameInstance.cpp
#include "MyGameInstance.h"
#include "CourseInfo.h"
#include "Student.h"
void UMyGameInstance::Init()
{
Super::Init();
UE_LOG(LogTemp, Log, TEXT("===== 델리게이트 예제 시작 ====="));
// 1. 학사 정보 시스템 생성
CourseInfo = NewObject<UCourseInfo>(this);
// 2. 학생 3명 생성
UStudent* Student1 = NewObject<UStudent>();
Student1->SetName(TEXT("학생1번"));
UStudent* Student2 = NewObject<UStudent>();
Student2->SetName(TEXT("학생2번"));
UStudent* Student3 = NewObject<UStudent>();
Student3->SetName(TEXT("학생3번"));
// 3. 델리게이트에 구독자 바인딩
CourseInfo->OnCourseInfoChanged.AddUObject(
Student1,
&UStudent::OnNotification
);
CourseInfo->OnCourseInfoChanged.AddUObject(
Student2,
&UStudent::OnNotification
);
CourseInfo->OnCourseInfoChanged.AddUObject(
Student3,
&UStudent::OnNotification
);
// 4. 학사 정보 변경 (자동으로 모든 구독자에게 알림)
CourseInfo->ChangeCourseInfo(TEXT("학교"), TEXT("변경된 학사 정보"));
UE_LOG(LogTemp, Log, TEXT("===== 델리게이트 예제 종료 ====="));
}
**실행 결과:**
===== 델리게이트 예제 시작 =====
[CourseInfo] 학사 정보가 변경되어 알림을 발송합니다.
[Student] 학생1번님이 알림을 받음 - 학교: 학교, 내용: 변경된 학사 정보
[Student] 학생2번님이 알림을 받음 - 학교: 학교, 내용: 변경된 학사 정보
[Student] 학생3번님이 알림을 받음 - 학교: 학교, 내용: 변경된 학사 정보
===== 델리게이트 예제 종료 =====
델리게이트 바인딩 메서드
1. AddUObject (가장 일반적)
// UObject의 멤버 함수 바인딩
MyDelegate.AddUObject(ObjectInstance, &UMyClass::MemberFunction);
특징 :
- Unreal Object의 멤버 함수 바인딩
- 자동 메모리 관리 (객체 소멸 시 자동 해제)
- 가장 안전하고 권장되는 방법
2. AddStatic
// 정적 함수 바인딩
MyDelegate.AddStatic(&MyStaticFunction);
특징 :
- 전역 또는 정적 함수 바인딩
- 객체 인스턴스 불필요
3. AddRaw
// 일반 C++ 객체의 멤버 함수 바인딩
MyDelegate.AddRaw(CppObject, &MyCppClass::MemberFunction);
특징 :
- Non-UObject C++ 클래스 바인딩
- 수동 메모리 관리 필요
4. AddLambda
// 람다 함수 바인딩
MyDelegate.AddLambda([](const FString& Param)
{
UE_LOG(LogTemp, Log, TEXT("Lambda: %s"), *Param);
});
특징 :
- 인라인 함수 정의
- 간단한 로직에 적합
- 캡처 사용 가능
5. AddSP (Shared Pointer)
// TSharedPtr로 관리되는 객체의 멤버 함수 바인딩
MyDelegate.AddSP(SharedObject, &MyClass::MemberFunction);
특징 :
- 스마트 포인터 기반 객체 바인딩
- 참조 카운팅 자동 관리
'기타 > [강의] 이득우의 언리얼 프로그래밍 Part1' 카테고리의 다른 글
| [이득우의 언리얼] 11. 언리얼 컨테이너 라이브러리 - 구조체, Map (0) | 2026.02.08 |
|---|---|
| [이득우의 언리얼] 10. 언리얼 컨테이너 라이브러리 - TArray, TSet (0) | 2026.02.07 |
| [이득우의 언리얼] 8. 언리얼의 C++ 설계 - 컴포지션 (0) | 2026.02.06 |
| [이득우의 언리얼] 7. 언리얼 C++ 설계 - 인터페이스 (0) | 2026.02.04 |
| [이득우의 언리얼] 6.언리얼 오브젝트 리플렉션 시스템 2 (0) | 2026.02.04 |