C++ 콜백 함수(Callback Function) 이해하기
- 최초 작성일: 2025년 6월 25일 (수)
목차
콜백 함수란?
콜백 함수는 특정 이벤트가 발생하거나 조건이 충족되었을 때 자동으로 호출되는 함수이다. 일반적으로 함수의 포인터나 객체를 통해 전달되어 프로그램 실행 중 특정 시점에 실행된다. 주로 이벤트 기반 프로그래밍이나 비동기 처리 방식에서 많이 활용된다.
콜백 함수가 필요한 이유
콜백 함수가 사용되는 대표적인 이유는 다음과 같다:
- 비동기 처리: 프로그램이 작업을 수행하는 동안 다른 이벤트나 작업이 완료되었을 때 특정한 동작을 실행할 수 있다.
- 유연한 설계: 호출되는 함수의 동작을 사용자가 원하는 대로 정의할 수 있다.
- 모듈 간 낮은 결합도 유지: 함수를 직접 호출하지 않고, 콜백을 통해 간접적으로 호출함으로써 코드의 모듈 간 의존성을 낮춘다.
기본적인 콜백 함수 예제
가장 단순한 형태의 콜백 함수 예제를 살펴보자. 아래의 예제는 두 정수를 더한 결과를 콜백 함수를 통해 전달하고 출력한다.
#include <iostream>
// 콜백 함수 정의
void CallbackFunction(int result) {
std::cout << "콜백이 호출됨, 결과값: " << result << std::endl;
}
// 콜백을 실행하는 함수 정의
void PerformTask(int a, int b, void(*callback)(int)) {
int sum = a + b;
callback(sum); // 콜백 함수 호출
}
int main() {
PerformTask(5, 10, CallbackFunction); // 콜백 함수 전달
return 0;
}
출력:
콜백이 호출됨, 결과값: 15
클래스 멤버 함수 콜백 예제
클래스의 멤버 함수를 콜백으로 사용할 경우를 예제로 들어 보자. 이 경우는 일반 함수 포인터 대신 std::function
을 활용한다.
#include <iostream>
#include <functional>
class Calculator {
public:
void Add(int a, int b, std::function<void(int)> callback) {
int sum = a + b;
callback(sum); // 결과값을 콜백 함수로 전달
}
};
class ResultHandler {
public:
void DisplayResult(int result) {
std::cout << "결과: " << result << std::endl;
}
};
int main() {
Calculator calc;
ResultHandler handler;
// 클래스 멤버 함수를 람다 표현식으로 감싸서 콜백 전달
calc.Add(7, 3, [&handler](int result) {
handler.DisplayResult(result);
});
return 0;
}
출력:
결과: 10
std::function을 이용한 콜백
C++11 이상에서 제공하는 std::function
은 다양한 호출 가능 객체(함수 포인터, 멤버 함수 포인터, 람다 표현식 등)를 통합적으로 관리할 수 있도록 돕는다. 다음은 파일 읽기 작업을 시뮬레이션한 직관적이고 이해하기 쉬운 예제이다.
#include <iostream>
#include <functional>
#include <string>
void ReadFile(const std::string& filename, std::function<void(const std::string&)> callback) {
// 파일 읽기 작업을 시뮬레이션
std::string fileContent = "파일 '" + filename + "' 의 내용을 성공적으로 읽었습니다.";
// 읽기 작업 완료 후 콜백 호출
callback(fileContent);
}
int main() {
ReadFile("example.txt", [](const std::string& content) {
std::cout << "콜백 호출됨: " << content << std::endl;
});
return 0;
}
출력:
콜백 호출됨: 파일 'example.txt' 의 내용을 성공적으로 읽었습니다.
콜백 사용 시 주의할 점
- 콜백 함수가 호출되는 시점의 상태를 명확하게 관리해야 한다. 예를 들어, 객체가 이미 파괴되었거나 자원이 유효하지 않을 때 호출되는 것을 방지해야 한다.
- 콜백 구조를 지나치게 복잡하게 설계하면 유지보수하기 어렵고 디버깅이 힘들어진다. 가능한 간결하고 명확한 설계를 유지하는 것이 좋다.
결론
콜백 함수는 함수 포인터, std::function
, 람다 표현식을 통해 다양한 방식으로 구현할 수 있으며, 이를 효과적으로 사용하면 더욱 유연하고 유지보수하기 쉬운 프로그램 설계를 할 수 있다. 특히, 비동기 처리 및 이벤트 기반 프로그램에서 그 효용성이 더욱 두드러진다.