[공부 내용 정리] 9강 언리얼 C++ 설계 III - 델리게이트

2025. 3. 19. 19:22·언리얼 공부/이득우의 언리얼 프로그래밍

0. 강의 내용 요약

더보기

언리얼 C++ 델리게이트

1. 느슨한 결합(Loose Coupling) 이 가지는 장점

  • 향후 시스템 변경 사항에 대해 손쉽게 대처할 수 있음.

2. 느슨한 결합(Loose Coupling) 으로 구현된 발행 구독 모델의 장점

  • 클래스는 자신이 해야 할 작업에만 집중할 수 있음.
  • 외부에서 발생한 변경 사항에 대해 영향받지 않음.
  • 자신의 기능을 확장하더라도 다른 모듈에 영향을 주지 않음.

3. 언리얼 C++ 의 델리게이트의 선언방법과 활용

  • 몇 개의 인자를 가지는가?
  • 어떤 방식으로 동작하는가? (MULTICAST 사용 유무 결정)
  • 언리얼 에디터와 함께 연동할 것인가? (DYNAMIC 사용 유무 결정)
  • 이를 조합해 적합한 매크로 선택

 

데이터 기반의 디자인 패턴을 설계할 때 유용하게 사용

 

 


 

 

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 UNREALDELEGATE_API UMyGameInstance : public UGameInstance
{
	GENERATED_BODY()
public:
	UMyGameInstance();

	virtual void Init() override;

private:
	UPROPERTY()
	TObjectPtr<class UCourseInfo> CourseInfo;

	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"
#include "Card.h"
#include "CourseInfo.h"

UMyGameInstance::UMyGameInstance()
{
	// CDO 의 생성 시점은 대체 언제인가?
	// 클래스 정보와 CDO 엔진 초기화 과정에서 생성되므로 게임 개발에서 안전하게 사용 가능
	// 생성자 코드에서 Class Default Object 의 기본값을 변경하는 경우에는 에디터를 끄고 컴파일해서 다시 실행해주기~
	SchoolName = TEXT("학교"); // 기본값 지정
}

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

	// CourseInfo 를 CDO 안에서 생성할수도 있지만 이번엔 외부에서(여기서) 필요할 때 생성하도록 할 것..
	CourseInfo = NewObject<UCourseInfo>(this); // outer 를 myGameInstance 로 설정 => CourseInfo 는 MyGameInstance 의 서브 오브젝트가 됨.


	UE_LOG(LogTemp, Log, TEXT("========================"));
	
	UStudent* Student1 = NewObject<UStudent>(); // 이 경우 이 오브젝트는 자동으로 소멸되므로 굳이 outer 설정 안 해줘도 됨.
	Student1->SetName(TEXT("학생1"));
	UStudent* Student2 = NewObject<UStudent>(); // 이 경우 이 오브젝트는 자동으로 소멸되므로 굳이 outer 설정 안 해줘도 됨.
	Student2->SetName(TEXT("학생2"));
	UStudent* Student3 = NewObject<UStudent>(); // 이 경우 이 오브젝트는 자동으로 소멸되므로 굳이 outer 설정 안 해줘도 됨.
	Student3->SetName(TEXT("학생3"));

	CourseInfo->OnChanged.AddUObject(Student1, &UStudent::GetNotification); // 연결!
	CourseInfo->OnChanged.AddUObject(Student2, &UStudent::GetNotification);
	CourseInfo->OnChanged.AddUObject(Student3, &UStudent::GetNotification);

	// 이제 CourseInfo 변경
	CourseInfo->ChangeCourseInfo(SchoolName, TEXT("변경된 학사 정보"));

	UE_LOG(LogTemp, Log, TEXT("========================"));
}

 

1.2 CourseInfo

더보기

1. 헤더 파일

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "CourseInfo.generated.h"

// 매크로 지정
// 두개의 인자를 가진 멀티캐스트 델리게이트
// 이제 이렇게 선언한 델리게이트를 멤버 변수로 선언해주면 됨
DECLARE_MULTICAST_DELEGATE_TwoParams(FCousreInfoOnChangedSignature, const FString&, const FString&);

/**
 * 
 */
UCLASS()
class UNREALDELEGATE_API UCourseInfo : public UObject
{
	GENERATED_BODY()
	
public:
	UCourseInfo();

	// 마치 객체처럼 델리게이트 정보를 멤버 변수로 심플하게 등로갷줭
	FCousreInfoOnChangedSignature OnChanged;

	void ChangeCourseInfo(const FString& InSchoolName, const FString& InNewContents);

private:
	UPROPERTY()
	FString Contents;
};

 

 

2. cpp 파일

// Fill out your copyright notice in the Description page of Project Settings.


#include "CourseInfo.h"

UCourseInfo::UCourseInfo()
{
	Contents = TEXT("기존 학사 정보");
}

void UCourseInfo::ChangeCourseInfo(const FString& InSchoolName, const FString& InNewContents)
{
	// 새로운 학사 정보 들어오면 변경해줌
	Contents = InNewContents;

	UE_LOG(LogTemp, Log, TEXT("[CourseInfo] 학사 정보가 변경되어 알림을 발송합니다."));
	OnChanged.Broadcast(InSchoolName, Contents); // OnChanged 에 연결된 모든 함수들한테 방송
}

 

1.3 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 UNREALDELEGATE_API UPerson : public UObject
{
	GENERATED_BODY()
	
public:
	UPerson();

	// forchinline 을 통해서 최대한 인라인이 되도록 선언..
	FORCEINLINE const FString& GetName() const { return Name; }
	FORCEINLINE void SetName(const FString& InName) { Name = InName; }

	FORCEINLINE class UCard* GetCard() const { return Card; }
	FORCEINLINE void SetCard(class UCard* InCard) { Card = InCard; }

protected:
	UPROPERTY() // 언리얼이 관리할 수 있는 속성으로 발전시키기위해 매크로 추가
	FString Name;

	//// 언리얼 엔진 4버전까지 정석이었음
	//// 컴포지션은 헤더로 포함하지 않고 전방선언해서 사용할수도 있음(의존성 최대한 없앨 수 있음)
	//// 보통 오브젝트는 포인터로 관리
	//UPROPERTY()
	//class UCard* Card;

	// 언리얼 엔진 5 
	// 원시포인터를 TObjectPtr 로 감싸줭
	// 얘는 기본 자체가 포인터라 * 연산자 안 써
	// 전방 선언은 그대로
	TObjectPtr<class UCard> Card;
};

 

 

2. cpp 파일

// Fill out your copyright notice in the Description page of Project Settings.


#include "Person.h"
#include "Card.h"

UPerson::UPerson()
{
	Name = TEXT("홍길동");

	// 이 서브오브젝트의 내부 식별자(Name)를 지정하기 위해서 인자로 TEXT 를 받음(FName 타입)
	Card = CreateDefaultSubobject<UCard>(TEXT("NAME_Card")); // NAME_ 이라는 접두사를 붙이면 코드를 보는 사람이 이것은 String 이 아니고 FName 이구나라고 알 수 있음
}

 

1.4 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 UNREALDELEGATE_API UStudent : public UPerson, public ILessonInterface
{
	GENERATED_BODY()
	
public:
	UStudent();

	// 인터페이스 상속했으니까 해당 인터페이스의 가상 함수를 무조건 구현해야함
	virtual void DoLesson() override;

	void GetNotification(const FString& School, const FString& NewCourseInfo);
};

 

 

2. cpp 파일

// Fill out your copyright notice in the Description page of Project Settings.


#include "Student.h"
#include "Card.h"

UStudent::UStudent()
{
	Name = TEXT("이학생");
	Card->SetCardType(ECardType::Student);
}

void UStudent::DoLesson()
{
	// LessonInterface 의 DoLesson 함수는 Super 로 가져올 수 없음
	// 얘의 Supter 는 Person 이기 때문.. 

	ILessonInterface::DoLesson(); // 어쩔 수 없이 직접 ILessonInterface 써줘야함

	UE_LOG(LogTemp, Log, TEXT("%s님은 공부합니다."), *Name);
}

void UStudent::GetNotification(const FString& School, const FString& NewCourseInfo)
{
	UE_LOG(LogTemp, Log, TEXT("[Student] %s님이 %s로부터 받은 메시지 : %s"), *Name, *School, *NewCourseInfo);
}

 

'언리얼 공부/이득우의 언리얼 프로그래밍' 카테고리의 다른 글
  • [공부 내용 정리] 11강 언리얼 컨테이너 라이브러리 - 구조체와 Map
  • [공부 내용 정리] 10강 언리얼 컨테이너 라이브러리 I - Array와 Set
  • [공부 내용 정리] 8강 언리얼 C++ 설계 II - 컴포지션
  • [공부 내용 정리] 7강 언리얼 C++ 설계 I - 인터페이스
dubu0721
dubu0721
dubu0721 님의 블로그 입니다.
  • dubu0721
    dubu0721 님의 블로그
    dubu0721
  • 전체
    오늘
    어제
    • 분류 전체보기 (352)
      • 프로그래밍언어론 정리 (5)
      • 컴퓨터네트워크 정리 (5)
      • 알고리즘&자료구조 공부 (64)
        • it 취업을 위한 알고리즘 문제풀이 입문 강의 (60)
        • 학교 알고리즘 수업 (3)
        • 실전프로젝트I (0)
      • 백준 문제 (204)
        • 이분탐색 (7)
        • 투포인트 (10)
        • 그래프 (11)
        • 그리디 (24)
        • DP (25)
        • BFS (21)
        • MST (7)
        • KMP (4)
        • Dijkstra (3)
        • Disjoints Set (4)
        • Bellman-Ford (2)
        • 시뮬레이션 (3)
        • 백트래킹 (15)
        • 위상정렬 (5)
        • 자료구조 (25)
        • 기하학 (1)
        • 정렬 (11)
        • 구현 (8)
        • 재귀 (8)
        • 수학 (8)
        • 트리 (1)
      • 유니티 공부 (11)
        • 레트로의 유니티 게임 프로그래밍 에센스 (11)
        • 유니티 스터디 자료 (0)
        • C# 공부 (0)
      • 유니티 프로젝트 (48)
        • 케이크게임 (13)
        • 점토게임 (35)
      • 언리얼 공부 (10)
        • 이득우의 언리얼 프로그래밍 (10)
      • 진로 (1)
      • 논문 읽기 (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    맵
    유니티 프로젝트
    골드메탈
    이분탐색
    유니티
    언리얼
    큐
    해시
    그래프
    C#
    자료구조
    dp
    수학
    이득우
    레트로의 유니티 프로그래밍
    백준
    시뮬레이션
    재귀
    바킹독
    백트래킹
    정렬
    유니티 공부 정리
    그리디
    이벤트 트리거
    BFS
    오블완
    우선순위큐
    티스토리챌린지
    스택
    투포인터
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
dubu0721
[공부 내용 정리] 9강 언리얼 C++ 설계 III - 델리게이트
상단으로

티스토리툴바