※ 제가 개인적으로 공부하는 것이라 요약하거나 책에서 빠진 내용이 있을 수 있습니다 ※
Section 1. 함수 객체란
함수 객체(Function Object)란 함수처럼 동작하는 객체. 객체가 '()' 연산자를 정의해야 하므로 '()' 연산자를 오버로딩한 객체다. 함수 객체는 함수자(Functor)라고도 불린다.
함수 객체 정의 예시
struct Functor
{
void operator() ()
{
cout << "함수 객체!" << '\n';
}
}
int main()
{
Functor functor;
functor(); // 멤버 함수 호출 fucntor.operator() -> "함수 객체!" 출력
}
functor는 객체지만 함수(functor())처럼 호출 가능. 매개변수를 갖는 함수 객체도 가능. operator() (int a, int b) -> functor(10, 20);
함수 객체의 장점
함수처럼 동작하는 객체이므로 다른 멤버 변수와 멤버 함수를 가질 수 있음. 일반 함수에서 하지 못하는 지원을 받을 수 있다. 또한, 함수 객체의 서명이 같더라도 객체 타입이 다르면 서로 전혀 다른 타입으로 인식. 속도도 일반 함수보다 함수 객체가 빠름. 함수의 주소를 전달하여 콜백하는 경우 이 함수 포인터는 인라인될 수 없지만(함수 포인터는 함수가 있어야 하므로 인라인 함수의 복사본 함수를 만들어 냄) 함수 객체는 인라인될 수 있고, 컴파일러가 쉽게 최적화할 수 있음.
장점을 보이는 예제. 내부적인 상태값을 갖는 함수 객체. Adder 클래스에는 정수를 누적하는 상태 변수 total이 있음
class Adder
{
int total;
public:
explicit Adder(int n=0) : total(n) { }
int operator() (int n)
{
return total += n;
}
};
int main()
{
Adder add(0); // 초기값 0
cout << add(10) << '\n'; // 10 누적 -> 10
cout << add(20) << '\n'; // 20 누적 -> 30
}
여기서 operator()(int n) 함수는 클래스 내부에 정의되므로 암묵적으로 인라인 함수가 된다. 또한, operator()(int n)와 서명이 같아도 타입이 다른 함수 객체는 Adder 클래스 객체에 대입하거나 복사 불가능.
함수 객체를 사용한 콜백 함수 구현
struct Functor1
{
void operator() (int n)
{
cout << n << ' ';
}
}
// 마찬가지로 Functor2, Functor3
int main()
{
...
for_each(arr, arr+5, Functor1()); // 임시 함수 객체 (Functor1())를 만들어 함수로 전달
...
}
2장 예제와 다른 점은 인자에 함수가 아닌 함수 객체를 전달했다는 것. 또한, 전달하는 함수 객체의 타입이 모두 다름(struct Functor1, struct Functor2, ..). 함수 오버로딩을 for_each에 미리 하지 않았는데 어떻게 이게 가능? 정답은 템플릿. 템플릿은 4장에서 더 자세히.
Section 2. 함수 객체 구현
STL에는 유용하게 사용할 수 있는 함수 객체가 내장돼 있다. 가장 대표적인게 less, greater. less는 < 연산자의 함수 객체, greater는 > 연산자의 함수 객체. 또한, less와 greater는 bool형을 반환하는 조건자(predicate)입니다. 조건자에 대한 내용은 9장에서.
Less 구현 예제
struct Less
{
bool operator() (int a, int b)
{
return a < b;
}
}
int main()
{
Less l;
cout << l(10, 20) << '\n'; // l 객체로 암묵적 함수 호출
cout << l(20, 10) << '\n';
cout << Less() (10, 20) << '\n'; // 임시 객체로 암묵적 함수 호출
cout << l.operator() (10, 20) << '\n'; // 명시적 호출
}
STL의 less 함수 객체 예제
#include <functional> // less<> 헤더
typedef less<int> Less;
int main()
{
Less l;
cout << l(10, 20) << '\n'; // l 객체로 암시적 함수 호출
cout << l.operator() (10, 20) << '\n'; // l 객체로 명시적 함수 호출
cout << Less(10, 20,) << '\n'; // 임시 객체로 암시적 함수 호출
cout << Less().operator() (10, 20) << '\n'; //임시 객체로 명시적 함수 호출
}
사용자 Less와 STL less의 결과는 다 같지만, STL less나 greater는 템플릿 클래스이므로 임시 객체를 less<int>(), greater<int>()와 같이 생성. 여기서 int는 비교할 값의 타입.
이것만은 알고 갑시다.
1. 다음 빈 칸을 채우세요.
1. 함수처럼 호출 가능한 클래스 객체를 가리켜 (_)라 한다.
- 함수 객체 or functor
2. 함수처럼 호출 가능한 클래스 객체는 (_) 연산자를 오버로딩해 생성합니다.
- () 연산자
2. 다음 Equal 클래스의 객체가 cmp일 때 두 정수가 같으면 true, 아니면 false를 반환하는 Equal 클래스를 작성하세요.
if (cmp(10, 20))
cout << "같다!" << '\n';
else
cout << "다르다!" << '\n';
답
class Equal
{
public:
bool operator() (int lh, int rh) const
{
return lh == rh;
}
}
3. 다음 Adder 클래스의 객체가 add일 때 두 정수의 합을 반환하는 Adder 클래스를 작성하세요
int sum = add(10, 20);
cout << "sum= " << sum << '\n';
답
class Adder
{
public:
int operator() (int lh, int rh) const
{
return lh + rh;
}
}
'C++ > C++ STL' 카테고리의 다른 글
C++ STL (뇌를 자극하는) - 4장. 함수 템플릿 (Section 2 ~ 3) (0) | 2025.07.28 |
---|---|
C++ STL (뇌를 자극하는) - 4장. 함수 템플릿 (Section 1) (2) | 2025.07.27 |
C++ STL (뇌를 자극하는) - 2장. 함수 포인터 (2) | 2025.07.24 |
C++ STL (뇌를 자극하는) - 1장. 연산자 오버로딩 (Section 6~7) (0) | 2025.07.23 |
C++ STL (뇌를 자극하는) - 1장. 연산자 오버로딩 (0) | 2025.07.08 |