1. 연산자 오버로딩

사용자가 새로 정의한 클래스형으로 선언한 변수의 경우, 이를 직접 기존 연산자를 사용하여 연산을 수행하는 것은 C++에 정의되어 있을 리 없다. 예를 들어, 다음 코드는 에러가 발생한다.

1
2
3
4
5
6
7
8
9
10
class CLASS1 {
public:
    int num1=1;
}N;

int main()
{
    std::cout << N + 2;
    return 0;
}

이런 경우를 위하여, C++에서는 클래스에 관련해서는 기존 연산자를 보통의 함수를 선언하는 형식을 따라 새로 정의할 수 있다. 다음 코드는 클래스명 CLASS1으로 선언된 클래스형 변수의 덧셈 연산을 새로 정의한 코드이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CLASS1 {
public:
    int num1 = 1;
}N;

int operator+(int a, CLASS1 b)
{
    return b.num1 + a;
}

int main()
{
    std::cout << 2 + N;
    return 0;
}

이처럼 연산자 앞에 ‘operator’라는 예약어를 써서 함수를 선언하듯 새로 함수를 선언하고 파라미터를 그 클래스형으로 선언하고 함수 내용 안에 코드를 적으면 그 함수 내용대로 연산이 수행된다. (단, 이후 그 클래스형에 관하여 재정의한 연산자를 사용하는 경우 연산자 재정의 때 파라미터에 쓴 변수형 선언 순서를 따라 연산자를 사용해야 한다. 예를 들어, 위 코드의 std::cout « 2 + N에서 2 + N을 N + 2로 바꿔 쓰면 에러가 발생한다.)

2. 클래스 멤버로서 연산자 재정의

클래스형을 선언할 때 멤버함수를 선언하듯 클래스의 멤버로서 연산자를 재정의할 수 있다. 이 경우 재정의된 연산자 함수는 파라미터로 전달된 변수그 클래스형으로 선언된 변수의 멤버 사이의 연산을 수행하므로(재정의된 연산자가 이항연산자인 경우) 클래스 멤버인 연산자 함수는 전역 함수로 선언될 때보다 파라미터를 한 개 덜 갖는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CLASS1 {
public:
    int num1=1;
    int operator+(int num1)
    {
        return this->num1 + num1;
    }
}N;


int main()
{
    std::cout << N + 2;
    return 0;
}

멤버 함수로 연산자를 재정의할 때에도 순서가 중요한데, 예를 들어 위 코드의 경우와 같이 재정의된 연산자가 파라미터로 그 클래스형과 다른 변수형을 받는 경우 그 연산자를 사용하는 수식의 왼쪽에는 항상 그 클래스형이 와야 한다. 위 코드의 std::cout « N + 2; 부분에서 N + 2를 2 + N으로 수정하면 에러가 발생한다.

위 코드는 멤버 연산자를 보통 연산자 사용하듯 사용하는 경우를 예로 들었지만, 멤버 연산자를 멤버 함수 호출하듯 호출하여 연산을 수행할 수도 있다. 예를 들어 위 코드의 std::cout « N + 2; 부분은 다음과 같이 수정해도 같은 결과를 출력한다.

1
    std::cout << N.operator+(2);

3. 함수객체

클래스 선언 때 () 연산자를 오버로딩하면 그 클래스 이름을 마치 함수 호출하듯 호출할 수 있으며(아주 약간 차이는 있다), 이때 그 클래스 선언문 내 재정의된 () 연산자 부분의 내용이 호출된다. 예를 들면 다음과 같은 코드를 쓸 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
class CLASS1 {
public:
    int operator()(int a, int b)
    {
        return a + b;
    }
};

int main()
{
    std::cout << CLASS1()(1, 2);
    return 0;
}

이를 객체(클래스)를 함수처럼 사용했다 해서 ‘함수객체(function object)’라 부른다.