본문 바로가기

[ C/ C++ 프로그래밍 ]/[ STL ]

[ 혼연 정리 ] 함수객체- 1 [함수객체]


ㅇ 함수 객체

STL의 알고리즘들은 전역 함수가 처리하며 문제를 풀기 위한 반복자 구간, 검색 대상, 채울 값 따위의 정보들이 함수의 인수로 전달된다.
알고리즘 함수들은 입력된 정보를 바탕으로 알아서 동작하지만 어떤 함수들은 내부에서 모든 동작을 다 처리하지 않거나
할수 없는 경우도 있다. 검색하고자 하는 값이 정확하게 어떤 조건인지, 정렬을 위해 요소를 어떤 방식으로 비교할 것인지를 함수가
마음대로 결정 할 수 없다.
이때 함수에게 좀더 구체적인 처리 방식을 지정하기 위해 사용자가 미리 만들어 놓은 함수 객체를 전달한다.
알고리즘 함수는 동작중에 사용자의 개입이 필요한 부분에 대해서 함수 객체를 호출하여 의사를 결정한다.
for_each 함수를 사용하면 순회를 대신 시킬 수 있으며 이때 순회 중에 어떤 작업을 할 것인가를 함수 객체로 지정한다.
for_each함수의 원형은 다음과 같다.

UniOp for_each ( InIt first, InIt last, UniOp op);

순회는 for_each가 되신 하되 순회중의 각 요소에 대한고유한 작업은 함수객체가 처리하는 방식이다.

예 제 : for_each

1 /// for_earch과함수객체에대한사용예
2 /// 예제에서는함수객체가아닌일반함수를넘겼다.
3
4 #include <iostream>
5 #include <vector>
6 #include <algorithm>
7
8 using namespace std;
9
10 void print(int _nValue)
11 {
12     printf("%d\n", _nValue);
13 }
14
15 void main()
16 {
17     int _nAri[] = { 2, 8, 5, 1, 9 };
18     vector<int>vi(&_nAri[0], &_nAri[5]);
19    
20     /// 정렬
21     sort(vi.begin(), vi.end());
22
23     /// 3번째인수에함수객체가들어가야한다. 일반함수도가능
24     for_each(vi.begin(), vi.end(), print);   // print : 함수 포인터
25 }






for_each 함수의 세번째 인수로 전달되는 대상을 함수객체(Function Object) 또는 펑크터(Functor)라고 하는데 예제에서는 함수 포인터로
넘겼다. 함수 포인터에만 국한 되는 것이 아니라 함수를 흉내낼 수 있는 모든 객체일 수 있다. 함수 객체(함수 호출 연산자인()를 오버로딩한객체)
를 통해 마치 함수를 호출 하듯이 객체를 호출 할 수 있다.

예 제 : functor

1 /// 함수객체에 대한 예
2 #include <iostream>
3 #include <vector>
4 #include <algorithm>
5
6 using namespace std;
7
8 /// class로선언할경우public을붙여주어야한다.
9 struct print
10 {
11     /// 함수객체선언
12     void operator()(int _nValue) const
13     {
14         printf("%d\n", _nValue);
15     }
16
17     void sum(int a)
18     {
19         printf("SUM %d \n",a);
20     }
21 };
22
23 void main()
24 {
25     int _nAri[] =2, 8, 5, 1, 9 };
26     vector<int> vi(&_nAri[0], &_nAri[5]);
27
28     /// print()는임시객체를생성함
29     for_each(vi.begin(), vi.end(), print());
30    
31     printf("\n");
32
33     /// 임시객체를 생성하지않는방법
34     print _sPRINT;
35     sort(vi.begin(), vi.end());
36     for_each(vi.begin(), vi.end(), _sPRINT);
37 }




for_each는 반복자 순서에 맞게 순회만 할뿐이며 실제 작업은 함수 객체가 한다. 일정 구간의 요소에 대해 어떤 작업을 하고 싶다면 for_each가 가장 쉬운 방법이다.





함수 객체는 클래스안에 함수를 캡츌화해 놓은 것으로 함수 포인터에 대한 일반화라고 할 수 있다.

STL이 함수 포인터를 확장하여 함수 객체라는 더 일반화된 개념을 사용하는 이유는 포인터에 비해 몇가지 장점이 있고 더 유연하기 때문이다.

① 함수 객체는 인라인이 가능해서 처리 속도를 대폭적으로 개선할 수 있다.

② 함수 객체는 객체이기 때문에 함수 연산자() 뿐만 아니라 필요한 멤버들을 추가로 더 가질 수 있다.

예제 : functionmem

 1 /// 함수객체의멤버변수이용
2 #include <iostream>
3 #include <vector>
4 #include <algorithm>
5 #include "accum.h"
6
7 using namespace std;
8
9
10 void main()
11 {
12     int ari[] = { 2, 8, 5, 1, 9 };
13     vector<int> svVI( ari[0], ari[1] );
14    
15     sort( svVI.begin(), svVI.end());
16     accum sTEST;
17
18     /// for_each로전달된f는값에의한전달이기때문에원본을직접
19     /// 변경하지않기때문에값을sTEST에다시대입한다.
20     sTEST = for_each( svVI.begin(), svVI.end(), sTEST );
21
22     printf("총합= %d\n", sTEST.m_nSum);
23 }



③ 멤버 뿐만 아니라 멤버 함수도 가질 수 있으며 생성자와 파괴자도 활용할 수 있다.
 생성자자는 멤버의 값을 원한는 대로 초기화 할 수 있다는 점에서 함수 객체에 대해서도 여전히 실용성이 높다.

예 제 : fuctorctor

1 /// 함수객체의생성자초기화
2 #include <iostream>
3 #include <string>
4 #include <vector>
5 #include <algorithm>
6
7 using namespace std;
8
9 struct print
10 {
11     string m_szMes;
12     print(string &_m) : m_szMes(_m) {}
13     void operator()(int a) const
14     {
15         cout << m_szMes;
16         printf("%d\n", a);
17     }
18 };
19
20 void main()
21 {
22     int ari[] = { 2, 8, 5, 1, 9 };
23     vector<int>vi(&ari[0], &ari[5]);
24
25     sort(vi.begin(), vi.end());
26
27     for_each( vi.begin(), vi.end(), print(string("요소값은")));
28     for_each( vi.begin(), vi.end(), print(string("다른메시지")));
29 }



 ④ 함수 객체는 타입이므로 템플릿의 인수로 사용될 수 있지만 함수 포인터는 단순한 값일 뿐이므로 템플릿의 인수로는 사용할 수 없다.

예 제 : functorpara

1 #include <iostream>
2 using namespace std;
3
4 template <typename T>
5 class SomeClass {};
6
7 struct print
8 {
9     void operator()(int a) const
10     {
11         printf("%d\n", a);
12     }
13 };
14
15
16 void func(int a)
17 {
18     printf("%d\n", a);
19 }
20
21 void main()
22 {
23     SomeClass<print> s1;    // 가능
24     //someClass<func> s2;    // 불가능
25 }


ps : 자세한 내용은  www.WinAPI.co.kr 참고