포스트

[함수 포인터] 02. 콜백 함수와 델리게이트

콜백 함수(Callback function)와 델리게이트(Delegate)는 프로그램의 유연성과 확장성을 증가시켜주는 고급 프로그래밍 기법입니다.

프로그래밍을 하다 보면 종종 다양한 상황에 맞추어 동작을 변경해야 할 때가 있습니다. 이러한 상황에서 콜백 함수와 델리게이트는 다양한 상황에서 동작을 변경시켜 주면서도 디커플링을 유지시켜주는, 매우 유연한 프로그래밍을 가능하게 하는 강력한 도구입니다.

미리 설명하면, 콜백 함수는 다른 함수를 호출할 때 그 함수를 인자로 전달하고, 이후에 해당 함수를 호출하는 방식으로 동작합니다.

델리게이트는 객체 지향 프로그래밍 언어에서 흔히 사용되는 개념으로, 함수를 변수처럼 다룰 수 있게 해줍니다.

콜백 함수(Callback function)

함수 포인터의 유용한 기능 중 하나는 함수를 다른 함수에 전달할 수 있다는 점입니다.

이때, 다른 함수에 인자로 전달되어 특정 이벤트나 조건이 발생했을 때 호출되는 함수를 콜백 함수라고 합니다.

이러한 방식은 비동기 처리, 이벤트 리스닝, 사용자 정의 동작 수행 등 다양한 상황에서 사용될 수 있습니다.

콜백 함수의 장단점

  1. 장점
    • 유연성: 콜백 함수를 사용하면 함수의 동작을 동적으로 변경할 수 있어 프로그램이 더 유연해집니다.
    • 재사용성: 특정 작업을 수행하는 콜백 함수를 여러 곳에서 재사용할 수 있습니다.
  2. 단점
    • 복잡성: 콜백 함수를 과도하게 사용하면 코드의 복잡성이 증가할 수 있습니다.

델리게이션(Delegation)과 델리게이트(Delegate)

델리게이션(Delegation)이란, 작업을 다른 사람에게 분배하고 위임하는 과정을 말합니다.

따라서, 프로그래밍에서 델리게이션 패턴은 객체 지향 프로그래밍에서 한 객체가 자신의 일부 기능을 다른 객체에 위임하는 것을 의미합니다. 이는 결합도를 낮추고 유연성을 증가시키기 위해 사용됩니다.

특히, 델리게이트(Delegate)는 C#과 같은 언어에서 사용되는 개념으로, 함수 포인터에 대응하는 개념입니다.

델리게이트를 사용하여 메서드(함수)를 변수에 할당하고, 이를 통해 메서드를 간접적으로 호출할 수 있습니다.

델리게이트의 특징

  • 유연성: 실행 시점에 이벤트 처리 할 함수를 변경함으로써, 동작을 유연하게 변경할 수 있습니다.
  • 이벤트 처리: 델리게이트는 이벤트 기반 프로그래밍에서 이벤트 핸들러로 사용할 수 있습니다.
  • 콜백 함수: 델리게이트는 콜백 함수의 매개변수로도 사용할 수 있습니다.
  • 멀티 캐스팅: 델리게이트는 C++의 함수 포인터와는 달리 1:N 관계, 즉 멀티캐스팅(multicasting)을 지원합니다.

즉, 델리게이트는 C++의 함수 포인터의 기능 뿐만 아니라, 이를 관리하고 1:N으로 호출하는 기능을 포함하는 객체입니다.

C++로 델리게이트 구현

C++로 델리게이트와 비슷한 기능을 가진 객체를 생성하고 호출하는 코드를 작성 해보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <vector>

class CustomDelegate
{
private:
	using FuncType = void(*)();
	std::vector<FuncType> delegates;

public:
	void Bind(FuncType func)
	{
		delegates.push_back(func);
	}

	void Broadcast()
	{
		for (void(*&func)() : delegates)
		{
			func();
		}
	}
};

void func1()
{
	std::cout << "func1" << '\n';
}
void func2()
{
	std::cout << "func2" << '\n';
}

int main()
{
	CustomDelegate customDelegate;

	customDelegate.Bind(func1);
	customDelegate.Bind(func2);

	customDelegate.Broadcast();
}

델리게이트의 1:N 호출에 대응하기 위해, vector로 함수 포인터들을 담는 배열을 하나 만들었습니다.

이때, 함수 포인터의 이름을 단순화 하기 위해 using을 사용했습니다.

(함수 포인터를 단순화하여 사용하는 글은 링크를 방문해 주세요.)

이후, Bind()Broadcast()로 함수 시그니처가 맞는 함수를 등록하거나 호출합니다.

일단, 이렇게만 구현해도 Unreal C++과 비슷하게 델리게이트 객체를 생성할 수 있었습니다.


참고

[함수 포인터] 01. 함수 포인터와 멤버 함수 포인터

[함수 포인터] 03. 일급 객체와 고차 함수

[함수 포인터] 04. 함수 포인터를 보기 좋게 만들기

이 기사는 저작권자의 CC BY-NC-ND 4.0 라이센스를 따릅니다.