관리 메뉴

Kim's Programming

C++ - 연산자 오버로딩(3/3) 본문

Programming/Cplusplus

C++ - 연산자 오버로딩(3/3)

Programmer. 2015. 9. 21. 14:20

오버로딩의 예


여기까지 주로 + 연산자만을 대상으로 연산자를 오버로딩하는 기본적인 방법에 대해 알아보았습니다. 덧셈 연산자가 가장 기본적이고 연산자의 일반적인 특징을 대변하는 대표적 연산자이기 떄문입니다. 이번엔 개별 연산자에 대해서 알아보며 기본 규칙외에도 연산자별로 고유한 규칙과 주의 사항들이 존재합니다. 모든 연산자에 일관되게 적용되는 규칙은 없고 연산자의 동작과 의미에 따라 오버로딩하는 방법이 다릅니다. 대개의 경우 상식과 일치하므로 어렵지는 않지만 연산자의 수가 많기 때문에 한꺼번에 다 공부할 수는 없습니다. 외우려기 보다는 연산자를 써야할때 상세하게 공부하는 것이 좋습니다. 연산자 몇개만 알아보겠습니다.


관계 연산자


관계 연산자는 동일한 타입의 두 객체에 대해 상등 및 대소를 비교합니다. 클래스별로 비교 방법이 다르므로 편리한 비교를 위해서는 관계 연 산자를 오버로딩하는 것이 좋습니다. 다음 예제는 Time객체의 관계 연산자를 오버로딩 한것이고 주의 사항이나 새로운 규칙은 없습니다. 같은 타입의 객체끼리 비교하는 것이므로 모두 멤버 연산자 함수로 정의했으며 얼마든지 전역 함수로도 만들 수 있습니다.

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
#include<iostream>
using namespace std;
 
class Time
{
    friend const Time operator +(int s, const Time &T);
private:
    int hour, min, sec;
public:
    Time(){};
    ~Time(){};
    Time(int h, int m, int s)
    {
        hour = h;
        min = m;
        sec = s;
    }
    void OutTime()
    {
        cout << hour << ":" << min << ":" << sec << endl;
    }
    bool operator ==(const Time &T) const
    {
        return (hour == T.hour&&min == T.min&&sec == T.sec);
    }
    bool operator !=(const Time &T) const
    {
        return !(*this == T);
    }
    bool operator> (const Time &T) const
    {
        if (hour > T.hour) return 1;
        if (hour < T.hour) return 0;
        if (min > T.min) return 1;
        if (min < T.min) return 0;
        if (sec > T.sec) return 1;
        return 0;
    }
    bool operator>=(const Time &T) const
    {
        return (*this == T || *this > T);
    }
    bool operator <(const Time &T) const
    {
        return !(*this >= T);
    }
    bool operator <=(const Time &T) const
    {
        return !(*this >T);
    }
};
void main()
{
    Time A(123);
    Time B(456);
    if (A == B)
        puts("A와 B는 같다");
    else
        puts("A와 B는 다르다");
}
cs

전저 두 객체가 같은지 점검하는 == 연산자를 보겠습니다. 두 객체가 완전히 같으려면 시분초의 요소가 모두 일치해야 합니다. 그래서 좌우변 객체의 hour,min,sec 멤버를 모두 비교한 결과를 &&로 묶에서 세 요소가 모두 일치하면 같은 것으로 판단하고 셋 중 하나라도 틀리면 다른 것으로 판단하도록 했습니다. 이 연산자가 정의되면 if(A == B)라는 연산식으로 두 객체의 상등 비교를 할 수 있습니다. 관계 연산자는 진위적인 연산을 하므로 리턴 타입이 bool형이 가장 적합합니다. 그러나 반드시 bool만 가능한것은 아닙니다. BOOl형일수도 int형도 얼마든지 가능하고 문자열 관련 타입의 경우 strcmp같은 표준 함 수와 보조를 맞추고 싶다면 int형을 리턴하는 것이 오히려 더 편리할 수도 있습니다. 연산자 하나만 놓고 본다면 당연히 bool형이어야겠지만 크다, 작다, 같다의 세가지 상태 중 하나를 리턴하려면 int타입이 더 어울립니다.


두 객체가 다른지를 점검하는 !=연산자는 직접 코드를 작성할 필요없이 ==연산자를 호출한결과를 반대로 뒤집어서 다시 리턴하면 됩니다. 다르다는 상태는 같지 않다는 상태와 의미가 동일하기 떄문에 두 함수의 본체를 각각 따로 만들 필요가 없습니다. 호출 객체인 *this와 우변 객체인 T에 대해 ==로 연산하면 이미 재정의 된 oeprator ==이 호출될 것이고 그 결과에 ! 연산을 적용하여 리턴했습니다. 좌변이 우변보다 더 큰지를 점검하는 > 연산은 나름대로 조금 복잡합니다. 시분초로 구성되는 Time 객체에서 무엇보다 가장 큰 단위인 시간이 우선적으로 비교되어야합니다. 시간이 더 크면 분초의 대소에는 상관없이 이 객체가 더 큰 것으로 쉽게 판단할 수 있습니다. 그래서 일단 hour 멤버를 비교해 보고 대소를 판단합니다. 만약 두 조건 (hour > T.hour, hour<T.hour)이 모두 만족하지 않을 경우는 다음 차례로 분을 비교하고 분 까지 일치한다면 초를 비교하여 대소를 판가름합니다. 최종적으로  초까지 비교해 보고 호출 객체의 초가 우변 객체보다 크지 않다면 이 경우는 작거나 같은 경우이므로 전체 연산의 결과는 거짓이 될 것입니다.


같다 크다를 비교하는 연산자가 완성되면 나머지 부등 비교 연산자들은 따로 코드를 작성할 필요가 없으며 이미 만들어진 연산자를 호출한 결과만 조합하면 됩니다. 남은 세 부등호 연산은 논리적으로 다음처럼 같다 크다, 그리고 아니다의 조합으로 바꿀 수 있습니다.



 연산 

 대체 연산

 크거나 같다

 같다 또는 크다

 작다

 크거나 같다가 아니다

 작거나 같다

 크다가 아니다

이렇게 바꿔진 조합을 적절한 조건문의 코드로 옮기기만 하면 됩니다. 주의할 것은 작다의 반대 조건이 크다가 아니라 크거나 같다라는 점입니다. 엄밀하게 논리를 따지지 않는 자연어에서와 수학에서의 대소 반대 조건이 다르므로 헷갈리지 말아야합니다.


증감 연산자


++연산자는 피연산자를 1 증가시키는 단항 연산자입니다. 비슷한 종류의 -- 감소 연산자도 있는데 두 연산자는 증감 방향만 다를 뿐 오버로딩하는 방법은 동일하므로 ++ 연산자에 대해서만 작성해보겠습니다. 다음 소스는 Time 객체에 ++ 연산자를 중복 정의합니다.

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
#include<iostream>
using namespace std;
 
class Time
{
    friend const Time operator +(int s, const Time &T);
private:
    int hour, min, sec;
public:
    Time(){};
    ~Time(){};
    Time(int h, int m, int s)
    {
        hour = h;
        min = m;
        sec = s;
    }
    void OutTime()
    {
        cout << hour << ":" << min << ":" << sec << endl;
    }
    Time & operator ++()
    {
        sec++;
        min += sec / 60;
        sec %= 60;
        hour += min / 60;
        min %= 60;
        return *this;
    }
    const Time operator ++(int dummy)
    {
        Time R = *this;
        ++*this;
        return R;
    }
};
void main()
{
    Time A(123);
    Time B;
    B = ++A;
    A.OutTime();
    B.OutTime();
    B = A++;
    A.OutTime();
    B.OutTime();
}
cs

증가 연산자는 값을 1 증가시키는데 구체적인 의미는 객체에 따라 조금씩 다르게 정의될 것입니다. 복소수 객체는 실수부만 1.0증가시키는 것이 합리적이고 Position객체는 (x,y)좌표를 오른쪽 아래로 한칸 이동 시킬 수도 있고 x만 증가시키든 y만 증가시키든 할 수도 있습니다. 시간인 경우는 초를 증가시키는 것으로 정의하는 것이 합리적이며 그래서 operator ++ 연산자는 sec멤버만 1증가시키는 형식으로 시간 객체에 대해 ++연산을 정의했습니다. 필요하다면 분이나 시를 증가시킬 수도 있습니다. ++ 연산자는 피연산자를 하나만 취하는 단항 연산자이며 위 소스의 operator ++은 멤버 연산자 함수로 정의되었으므로 이 함수는 호출하는 객체 자신이 피연산자가 됩니다. 따라서 이 함수는 별도의 인수를 가질 필요가 없습니다.


'Programming > Cplusplus' 카테고리의 다른 글

C++ - 클래스 상속(2/3)  (0) 2015.10.12
C++ - 클래스 상속(1/3)  (0) 2015.09.22
C++ - 연산자 오버로딩(2/3)  (0) 2015.09.20
C++ - 연산자 오버로딩(1/3)  (1) 2015.09.20
C++ - 캡슐화(3/3)  (0) 2015.09.19