본문 바로가기
  • 쓸쓸한 개발자의 공부방
C++

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

by 심찬 2022. 1. 1.

 

연산자 재정의 (operator overloading)

 

연산자 재정의란 +, -, * 의 연산자를 함수로 만들 수 있다.

operator+, operator-, operator*

#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;
    
    Point p1(1,1);
    Point p2(2,2);
    Point p3 = p1 + p2; // operator+(p1, p2)
            // operator+(Point, Point)
            // p1.operator+(p2) => operator+(Point) ¸âšöÇÔźö
            
    
}

 

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

a,b 모두 primitive type(int, double 등)의 경우는 일반적인 덧셈을 수행한다.

a,b 하나라도 사용자 정의 타입의 경우 "operator+함수"를 찾게 된다.

 방법1. 멤버 함수 검색

   a.operator+(b)

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

   operator+(a,b)

main.cpp:17:19: error: no match for ‘operator+’ (operand types are ‘Point’ and ‘Point’)
   17 |     Point p3 = p1 + p2; // operator+(p1, p2)
      |                ~~ ^ ~~
      |                |    |
      |                |    Point
      |                Point

 

operator+ 함수 구현 (문제 발생되는 경우)

 

* 일반 함수로 opeator+를 구현하는 경우 유의할 점이 하나 있다. 아래와 같이 코드 구현시 문제가 발생한다.

#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;
    }
};

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(); // 3, 3
}

아래와 같이 문제가 발생한다. private 에 접근 불가하기 때문이다. 그래서 friend 함수로 operator+를 정의해줘야 한다.

main.cpp:21:10: error: ‘int Point::x’ is private within this context
   21 |     temp.x = p1.x + p2.x;
      |          ^
main.cpp:5:9: note: declared private here
    5 |     int x;
      |         ^
main.cpp:21:17: error: ‘int Point::x’ is private within this context
   21 |     temp.x = p1.x + p2.x;
      |                 ^
main.cpp:5:9: note: declared private here
    5 |     int x;
      |         ^
main.cpp:21:24: error: ‘int Point::x’ is private within this context
   21 |     temp.x = p1.x + p2.x;
      |                        ^
main.cpp:5:9: note: declared private here
    5 |     int x;
      |         ^
main.cpp:22:10: error: ‘int Point::y’ is private within this context
   22 |     temp.y = p1.y + p2.y;
      |          ^
main.cpp:6:9: note: declared private here
    6 |     int y;
      |         ^
main.cpp:22:17: error: ‘int Point::y’ is private within this context
   22 |     temp.y = p1.y + p2.y;
      |                 ^
main.cpp:6:9: note: declared private here
    6 |     int y;
      |         ^
main.cpp:22:24: error: ‘int Point::y’ is private within this context
   22 |     temp.y = p1.y + p2.y;
      |                        ^
main.cpp:6:9: note: declared private here
    6 |     int y;
      |         ^

 

operator+ 함수 구현 (friend ~~)

 

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

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

 타입의 크기가 큰 경우 call by value보다 const 참조가 좋다.  Point p1  ==>  const Point& p1

#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(); // 3, 3
}

 

멤버 함수로 구현하는 operator+

 

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

#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;  // operator+(p1, p2)
                         // p1.operator+(p2)
    
    p3.print(); 
}

 

 

멤버 함수 VS 멤버가 아닌 함수

 

operator+ 함수 '인자의 개수'

  멤버 함수 1개

  멤버가 아닌 함수 2개

 

멤버와 멤버가 아닌 함수를 동시에 제공하면 멤버함수가 우선시 된다.

a+b에서 첫번째 인자인 a의 타입이 user type 이면 멤버 함수와 멤버가 아닌 함수 모두 사용가능

a+b에서 첫번째 인자인 a의 타입이 user type이 아니면 멤버가 아닌 일반 함수로만 만들 수 있다.

#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;  }

    // 멤버로 구현
    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)
                        
    p1 + 1; // 1. p1.operator+(int)
            // 2. operator+(Point, int)
            
    1 + p1; // 1. 1.operator+(Point) - 만들수 없다.
            // 2. operator+( int, Point) - 만들수 있다.
    
    
    
    p3.print(); 
}

 

 

 

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;  }

    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; 
    
    operator+(p1, p2); // 
    p1.operator+(p2);
    
    p3.print(); 
}

 

 

연산자 재정의 문법 주의사항

1. 인자가 모두 primitive 타입인 경우는 오버로딩 할 수 없다.

2. 다음의 연산자는 오버로딩 할 수 없다.

   .*    ::    sizeof    typeid

   static_cast    dynamic_cast    reinterpret_cast   const_cast

   . : C++부터 오버로딩 가능

3. 멤버 함수로만 오버로딩 가능한 연산자   =  ()   {}   ->

4. 새로운 연산자를 만들거나 인자의 개수를 변경하거나 연산자 우선순위를 변경할 수 없다.

5. 디폴트 파라미터를 사용할 수 없다.

 

int operator+(int a, int b)
{
    return a - b;
}

//3 + 2;

//p.print();

Point operator+(const Point& p, int n )
{
    //.....
}

Point p1;
Point p2 = p1 + ;// 1;

 

알고 나면 간단하지만 모르면 혼란스러운 연산자 재정의 문법은 꼭 알아 둡시다.

기초 중의 기초!!!

 

'C++' 카테고리의 다른 글

[C++] exception (예외처리)  (0) 2022.01.10
[C++] cout, endl 원리, operator<< 재정의  (0) 2022.01.02
[C++] 다중 상속 (multiple inheritance)  (0) 2021.12.31
[C++] 상속과 RTTI  (0) 2021.12.30
[C++] RTTI (Run Time Type Information)  (0) 2021.12.29

댓글