[C++] 함수 객체 (Function Object)

Seongcheol Jeon·2025년 7월 13일
0

CPP

목록 보기
47/47
post-thumbnail

함수 객체란?

함수 객체(Function Object)함수처럼 동작하는 객체이다. 함수처럼 동작하려면 객체가 ( )연산자를 정의해야 한다. 다시 말해 ( )연산자를 오버로딩한 객체이다. 함수 객체는 함수자(Functor)라 불리기도 한다.

#include <iostream>

using namespace std;

void Print()
{
    cout << "전역 함수!" << endl;
}

struct Functor
{
    void operator()()
    {
        cout << "함수 객체!" << endl;
    }
};

int main()
{
    Functor functor;

    Print(); // 전역 함수 호출
    functor(); // 멤버 함수 호출 functor.operator()와 같다.
    
    return 0;
}

functor는 객체지만 함수처럼 호출할 수 있다. ( )연산자 멤버 함수를 호출한다. 당연한 이야기지만 매개변수 리스트를 갖는 함수 객체를 만들수 있다.

#include <iostream>

using namespace std;

void Print(int a, int b)
{
    cout << "전역 함수: " << a << ',' << b << endl;
}

struct Functor
{
    void operator()(int a, int b)
    {
        cout << "함수 객체: " << a << ',' << b << endl;
    }
};

int main()
{
    Functor functor;

    Print(10, 20); // 전역 함수 호출
    functor(10, 20); // 멤버 함수 호출 functor.operator()와 같다.
    
    return 0;
}

functor(10, 20) 문장은 실제 functor.operator()(10, 20)처럼 멤버 함수를 호출한다.
일반 함수보다 복잡해 보이는 함수 객체를 사용하는 이유가 무엇일까?

함수 객체(Functor)의 장점
함수 객체는 함수처럼 동작하는 객체이므로 다른 멤버 변수와 멤버 함수를 가질 수 있고, 일반 함수에서 하지 못하는 지원을 받을 수 있다. 또한, 함수 객체의 섬여이 같더라도 객체 타입이 다르면 서로 전혀 다른 타입으로 인식한다.
속도도 일반 함수보다 함수 객체가 빠르다. 함수의 주소를 전달하여 콜백하는 경우 이 함수 포인터는 인라인될 수 없지만(함수 포인터는 함수가 있어야 하므로 인라인 함수의 복사본 함수를 만들어 낸다) 함수 객체인라인될 수 있고, 컴파일러가 쉽게 최적화할 수 있다.

다음은 함수 객체의 장점을 보이기 위한 예제이다.

#include <iostream>

using namespace std;

class Adder
{
public:
    explicit Adder(int n = 0) : total(n) {}
    int operator()(int n)
    {
        return total += n;
    }
private:
    int total;
};

int main()
{
    Adder add(0);

    cout << add(10) << endl;
    cout << add(20) << endl;
    cout << add(30) << endl;

    return 0;
}

/* 결과
10
30
60
*/

초깃값 0을 시작으로 add() 함수를 호출할 때마다 정수를 누적하고 반환한다. 여기서 operator()(int n) 함수는 클래스 내부에 정의되므로 암묵적으로 인라인 함수 가 된다. 또한 operator()(int n)과 서명이 같더라도 타입이 다른 함수 객체는 Adder 클래스 객체에 대입하거나 복사할 수 없다.

#include <algorithm>
#include <iostream>

using namespace std;

// client
struct Functor1
{
    void operator()(int n)
    {
        cout << n << " ";
    }
};

struct Functor2
{
    void operator()(int n)
    {
        cout << n * n << " ";
    }
};

struct Functor3
{
    void operator()(int n)
    {
        cout << "정수 : " << n << endl;
    }
};

int main()
{
    int arr[5] = { 10, 20, 30, 40, 50 };

    // 임시 함수 객체(Functor1)을 만들어 함수로 전달
    for_each(arr, arr + 5, Functor1());

    cout << endl << endl;

    // 임시 함수 객체(Functor2)을 만들어 함수로 전달
    for_each(arr, arr + 5, Functor2());

    cout << endl << endl;

    // 임시 함수 객체(Functor2)을 만들어 함수로 전달
    for_each(arr, arr + 5, Functor3());

    return 0;
}

/* 결과
10 20 30 40 50

100 400 900 1600 2500

정수 : 10
정수 : 20
정수 : 30
정수 : 40
정수 : 50
/*

함수 객체 구현

STL에는 유용하게 사용할 수 있는 함수 객체가 내장돼 있다. 그중 대표적인 함수 객체lessgreater이다.

less< 연산자의 함수 객체이며, greater> 연산자의 함수 객체이다. 또한 lessgreaterbool 형을 반환하는 조건자(predicate)이다.

다음은 두 정수를 입력받아 < 연산을 수행하는 함수와 함수 객체를 구현한 예이다.

#include <iostream>

using namespace std;

bool Pred_less(int a, int b)
{
    return a < b;
}

struct Less
{
    bool operator()(int a, int b)
    {
        return a < b;
    }
};

int main()
{
    Less less;

    cout << Pred_less(10, 20) << endl;
    cout << Pred_less(20, 10) << endl;
    cout << endl;
    cout << less(10, 20) << endl; // less 객체로 암묵적 함수 호출
    cout << less(20, 10) << endl; // less 객체로 암묵적 함수 호출
    cout << Less()(10, 20) << endl; // 임시 객체로 암묵적 함수 호출
    cout << Less()(20, 10) << endl; // 임시 객체로 암묵적 함수 호출
    cout << endl;
    cout << less.operator()(10, 20) << endl; // less 객체로 명시적 함수 호출
    cout << Less().operator()(10, 20) << endl; // 임시 객체로 명시적 함수 호출

    return 0;
}

다음은 STLless 함수 객체를 사용한 예이다.

#include <functional> // less<> 헤더
#include <iostream>

using namespace std;

// typedef less<int> Less;
using Less = less<int>;

int main()
{
    Less less;

    cout << less(10, 20) << endl; // less 객체로 암묵적 함수 호출
    cout << less(20, 10) << endl; // less 객체로 암묵적 함수 호출
    cout << Less()(10, 20) << endl; // 임시 객체로 암묵적 함수 호출
    cout << Less()(20, 10) << endl; // 임시 객체로 암묵적 함수 호출
    cout << endl;
    cout << less.operator()(10, 20) << endl; // less 객체로 명시적 함수 호출
    cout << Less().operator()(10, 20) << endl; // 임시 객체로 명시적 함수 호출

    return 0;
}

다음은 유용하게 쓰이는 plus와 minus 함수 객체를 구현한 예이다.

#include <functional> // plus<>, minus<> 헤더
#include <iostream>

using namespace std;

struct Plus
{
    int operator()(int a, int b)
    {
        return a + b;
    }
};

struct Minus
{
    int operator()(int a, int b)
    {
        return a - b;
    }
};

int main()
{
    cout << Plus()(10, 20) << endl;
    cout << Plus()(20, 10) << endl;
    cout << Minus()(10, 20) << endl;
    cout << Minus()(20, 10) << endl;
    cout << endl;
    cout << plus<int>()(10, 20) << endl;
    cout << plus<int>()(20, 10) << endl;
    cout << minus<int>()(10, 20) << endl;
    cout << minus<int>()(20, 10) << endl;

    return 0;
}

/* 결과
30
30
-10
10

30
30
-10
10
*/

사용자 정의 Plus, MinusSTLplus, minus 함수 객체의 결과는 같다. STL에서 함수 객체는 곳곳에 사용되며 중요한 역할을 한다.

0개의 댓글