C++ ()연산자 오버로딩과 펑터(Functor)

C++ ()연산자 오버로딩과 펑터(Functor)


() 연산자를 오버로딩을 하게 되면 객체를 함수처럼 사용할 수 있게 된다.


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
43
44
45
46
#include <iostream>
using namespace std;
 
class Point
{
    int xpos, ypos;
public :
    Point(int x = 0int y = 0) : xpos(x), ypos(y) {}
    Point operator+(const Point &pos) const
    {
        return Point(xpos + pos.xpos, ypos + pos.ypos);
    }
    friend ostream& operator<<(ostream &os, const Point &pos);
};
ostream& operator<<(ostream &os, const Point &pos)
{
    os << '[' << pos.xpos << ", " << pos.ypos << ']' << endl;
    return os;
}
 
class Adder
{
public :
    int operator()(const int &n1, const int &n2)
    {
        return n1 + n2;
    }
    double operator()(const double &e1, const double &e2)
    {
        return e1 + e2;
    }
    Point operator()(const Point &pos1, const Point &pos2)
    {
        return pos1 + pos2;
    }
};
 
int main()
{
    Adder adder;
    cout << adder(13<< endl;
    cout << adder(1.53.7<< endl;
    cout << adder(Point(34), Point(79));
 
    return 0;
}
cs


위와 같은 예제가 있다.


40행에서 class Adder을 선언해준다.

41행에서 출력을 해주는데 adder 클래스는 () 연산자를 오버로딩을 하고 있다. 24행으로 이동해서 n1 + n2 결과값을 반환해서 출력해주고 있다.

42행에서 1.5와 3.7을 넘겨주고 28행에서 e1 + e2 결과값을 반환해서 출력해주고 있다.


43행에서 Point클래스를 인자값으로 넘겨주고 있다. 32행으로 넘어가서 먼저 Point(7, 9)를 실행한다.

그럼 생성자가 호출이 되어 8행 생성자를 실행한다. 그럼 xpos = 7, ypos = 9 값이 들어간다.

그리고 Point(3, 4)가 실행이 되어 8행 생성자를 실행한다. 그럼 xpos = 3, ypos = 4 값이 들어간다.

그리고 pos1 + pos2 를 실행하는데 + 연산자를 Point 클래스에서 오버로딩을 했다.

그럼 다시 9행으로 넘어가서 xpos와 ypos를 각각 덧셈을 해준다. return Point 이니까 다시 한번 생성자를 호출하게 된다.

그럼 11행에서 생성한 Point는 xpos = 10, ypos = 13이 된다. 그리고 Point를 반환한다.


다시 43행으로 넘어와 << 연산자를 실행하는데 Point 클래스에서 << 연산자 오버로딩을 해줬다.

17행에서 출력을 해준다.


실행 과정은 이렇게 된다.



< 실행 결과 >


펑터란? 펑터의 위력은?


펑터란? : 위의 예제에서 Adder 클래스와 같이 함수처럼 동작하는 클래스를 '펑터(Functor)'라 한다.

 그리고 '함수 오브젝트(Function Object)'라고도 불린다.


펑터는 함수 또는 객체의 동작방식에 유연함을 제공할 때 주로 사용된다.

말보다는 예제를 통해서 확인해보자.


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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <iostream>
using namespace std;
 
class SortRule
{
public :
    virtual bool operator()(int num1, int num2) const = 0;
};
 
class AscendingSort : public SortRule // 오름차순
{
public :
    bool operator()(int num1, int num2) const
    {
        if (num1 > num2)
            return true;
        else return false;
    }
};
 
class DescendingSort : public SortRule // 내림차순
{
public :
    bool operator()(int num1, int num2) const
    {
        if (num1 < num2)
            return false;
        else return true;
    }
};
 
class DataStorage
{
    int *arr, idx;
    const int MAX_LEN;
public :
    DataStorage(int arrlen) : idx(0), MAX_LEN(arrlen)
    {
        arr = new int[MAX_LEN];
    }
    void AddData(int num)
    {
        if (MAX_LEN <= idx)
        {
            cout << "더 이상 저장이 불가능합니다." << endl;
            return;
        }
        arr[idx++= num;
    }
    void ShowAllData()
    {
        for (int i = 0; i < idx; i++)
            cout << arr[i] << ' ';
        cout << endl;
    }
    void SortData(const SortRule &functor)
    { //버블정렬 사용
        bool flag = true;
        for(int i =0; i<(idx - 1); i++)
            for (int j = 0; j < (idx - 1); j++) {
                flag = false;
                if (functor(arr[j], arr[j + 1]))
                {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1= temp;
                    flag = true;
                }
            }
    }
};
 
int main()
{
    DataStorage storage(5);
    storage.AddData(40);
    storage.AddData(30);
    storage.AddData(50);
    storage.AddData(20);
    storage.AddData(10);
 
    storage.SortData(AscendingSort());
    storage.ShowAllData();
 
    storage.SortData(DescendingSort());
    storage.ShowAllData();
    return 0;
}
cs

7행을 보면 가상함수(virtual)로 되어있다. 이것은 자식 클래스에서 재정의 하겠다는 것이다.
class AscendingSort와 DescendingSort는 오름차순과 내림차순을 정의하고 있다.

75행을 보면 DataStorage 클래스를 선언하고 5를 인자값으로 보내줬다.
37행에서 생성자를 실행하고 MAX_LEN = 5 저장이 된다.
그리고 arr은 동적할당으로 힙 메모리에 5개 만큼의 배열이 생성이 된다. (위 예제에서는 힙 메모리 해제를 안하겠다.)

76~80행에서 데이터 값을 넣어주고 있다.
82행에서 AscendingSort() 클래스를 임시객체로 선언해서 (56행)주소값을 받고있다.
SortRule 클래스는 AsendingSort와 DescendingSort 클래스를 상속 하고 있기에 객체를 인자로 전달이 가능하다.

이것이 펑터를 정의하는 이유라고 하는데... 이런게 유연함인가?? 뭐.. 이렇게도 사용이 된다! 라고 알고있자.





댓글

Designed by JB FACTORY