프로그래밍/C++

[C++] 연산자 재정의 (operator overloading)

갓똥 2019. 12. 14. 14:47
728x90
반응형

1. 연산자 재정의 기본 개념

#include <iostream>

class Point {
    int x;
    int y;
public:
    Point( int a = 0, int b = 0 ) : x(a), y(b) {}
};

int main() {
    int n = 1 + 2; // 3
    
    Point p1(1, 1);
    Point p2(2, 2);
    Point p3 = p1 + p2; // ?
    // operator+(p1, p2) -> operator+(Point, Point)
}

  ① +, -, *, 등의 연산자도 함수로 만들 수 있다.

    => operator+, operator-, operator*

 


2. a + b 를 컴파일러가 해석하는 방법

  ① a, b가 모두 primitive type (int, double 등) 인 경우

    => 일반적인 덧셈을 수행한다.

 

  ② a, b중 한 개라도 사용자 정의 타입이 있는 경우

    => operator+ 함수를 찾게 된다.

    => 방법1. 멤버 함수 검색

        ▶ a.operator+(b)

    => 방법2. 멤버가 아닌 일반 함수 검색

        ▶ operator+(a, b)

 


3. 멤버가 아닌 일반 함수로 구현하는 operator+

#include <iostream>

class Point {
    int x;
    int y;
public:
    Point( int a = 0, int b = 0 ) : x(a), y(b) {}
    
    void print() const {
        std::cout << x << ", " << y << std::endl;
    }
    
    friend Point operator+(const Point& p1, const Point& p2);
};

Point operator+(const Point& p1, const Point& p2) {
    Point temp;
    temp.x = p1.x + p2.x;
    temp.y = p1.y + p2.y;
    return temp;
}

int main() {
    Point p1(1, 1);
    Point p2(2, 2);
    Point p3 = p1 + p2; // operator+(p1, p2)
    
    p3.print();
}

  ① +는 이항 연산자 이므로 인자가 2개 이어야 한다.

 

  ② 타입의 크기가 큰 경우 call by value보다는 const 참조가 좋다.

 

  ③ friend 함수로 만드는 경우가 많다.

 


4. 멤버 함수로 구현하는 operator+

#include <iostream>

class Point {
    int x;
    int y;
public:
    Point( int a = 0, int b = 0 ) : x(a), y(b) {}
    
    void print() const {
        std::cout << x << ", " << y << std::endl;
    }
    
    // 멤버로 만드는 operator+
    Point operator+( const Point& p ) {
        Point temp;
        temp.x = p.x + x;
        temp.y = p.y + y;
        return temp;
    }
};

int main() {
    Point p1(1, 1);
    Point p2(2, 2);
    Point p3 = p1 + p2; // p1.operator+(p2)
    
    p3.print();
}

  ① +는 이항 연산자 이지만 인자가 1개 이어야 한다.

 


5. 멤버 함수 vs 멤버가 아닌 함수

#include <iostream>

class Point {
    int x;
    int y;
public:
    Point( int a = 0, int b = 0 ) : x(a), y(b) {}
    
    void print() const {
        std::cout << x << ", " << y << std::endl;
    }
    
    // 멤버로 만드는 operator+
    Point operator+( const Point& p ) {
        std::cout << "member" << std::endl;
    
        Point temp;
        temp.x = p.x + x;
        temp.y = p.y + y;
        return temp;
    }
    
    friend Point operator+(const Point& p1, const Point& p2);
};

// 일반 함수로 구현
Point operator+(const Point& p1, const Point& p2) {
    std::cout << "non member" << std::endl;
    
    Point temp;
    temp.x = p1.x + p2.x;
    temp.y = p1.y + p2.y;
    return temp;
}

int main() {
    Point p1(1, 1);
    Point p2(2, 2);
    Point p3 = p1 + p2; // 1. p1.operator+(p2)
                        // 2. operator+(p1, p2)
    p3.print();
}
실행결과

member
3, 3

  ① operator+ 함수의 인자의 개수

    => 멤버 함수 : 1개

    => 멤버가 아닌 함수 : 2개

 

  ② 멤버와 멤버가 아닌 함수를 동시에 제공하면

    => 멤버함수가 우선 시 된다.

 

int main() {
    Point p1(1, 1);
    Point p2(2, 2);
    Point p3 = p1 + p2; // 1. p1.operator+(p2)
                        // 2. operator+(p1, p2)
                        
    p1 + 1; // 1. p1.operator+(int)
            // 2. operator+(Point, int)
    
    1 + p1; // 1. 1.operator+(Point) - 만들 수 없다.
            // 2. operator+(int, Point) - 만들 수 있다.
}

  ③ a + b에서 첫 번째 인자인 a의 타입이

    => user type이면

        ▶ 멤버 함수와 멤버가 아닌 함수 모두 사용가능

 

    => user type이 아니면

        ▶ 멤버가 아닌 일반 함수로만 만들 수 있다.

 

  ④ 멤버 함수가 좋을까 ? 멤버가 아닌 함수가 좋을까 ? 

    => 개발자들마다 의견이 다름...

 


6. operator+ 함수를 호출하는 방법

int main() {
    Point p1(1, 1);
    Point p2(2, 2);
    
    Point p3 = p1 + p2; // 1. 컴파일러에 의해
    operator+(p1, p2);  // 2. 일반 함수로
    p1.operator+(p2);   // 3. 멤버 함수로
}

  ① 컴파일러에 의해

    => Point p3 = p1 + p2;

    => 멤버 함수 우선

 

  ② 일반 함수로

    => operator+(p1, p2);

 

  ③ 멤버 함수로

    => p1.operator+(p2);

728x90
반응형