-
[c++] 연산자 오버로딩 (operator overloading) (1)C++ 2023. 1. 8. 18:03
말그대로 연산자를 오버로딩하는 것이다.
기본자료형만 가지고 할 수 있는
덧셈,뺄셈, 곱셈, 나눗셈, 대입연산을
객체도 할 수 있게 만들 수 있다.
객체 + 객체 라는 코드가 있으면
이때 객체 간의 연산이므로
(정의되어 있는게 아니므로!)
어떻게 연산작업이 수행될지 직접 정의해주어야함
따라서 해당 객체 클래스 안에 호출될 연산자함수를 정의해주는 것임
형식은 operator+() 꼴.
예를 들어 보자면,
Point 클래스의 p1 + p2 라는 코드가 있으면,
p1.operator+(Point& ref) 라고 정의된 함수가 호출되는 식이다!
class Point { private: int xpos, ypos; public: Point(int x = 0, int y = 0) : xpos(x), ypos(y) { // empty } // 덧셈연산 Point& operator+(const Point& ref) { Point pos(xpos + ref.xpos, ypos + ref.ypos); return pos; } // 전위증가 const Point& operator++() { xpos++; ypos++; return *this; } // 후위증가 const Point& operator++(int) { const Point temp(xpos, ypos); xpos++; ypos++; return temp; } };
[연산자 오버로딩의 return 형이 클래스 타입인 이유(void 가 아닌 이유)]
여기서 오버로딩 함수의 반환형으로
왜 Point& 즉, 참조형을 쓰는지 궁금할 수 있다.
void operator++() { xpos++; ypos++; }그냥 이렇게 void 형으로 써도 되는데 말이다
참조형으로 반환하는 이유는
연속적으로 연산자를 적용할때를 대비해서 그런거다
예를들어
가장 보편적으로 쓰는 경우
Point a(1,0); Point b(3,4); Point c; c = a + b;이 경우에 a + b 를 진행한 후에
c에 대입할 객체가 반환되어야한다
따라서 return형이 void 형이 아닌 클래스type인 것이다
특별한 경우를 예시로 들면,
++(++pos); ++(pos.operator++());위와 같은 경우 ++ 전위증가를 두 번 연속으로 하는데, 이때 만약 void 형이면 두번째 ++ 을 적용할 수 없다!
따라서 연속으로 연산을 진행하려면 꼭 리턴값이 참조값 반환형으로 정의되어야한다!
그래서 비교연산 ( > < == ) 빼고는 다 해당 객체 타입으로 리턴한다고 보면 된다
비교연산은 bool 로 리턴한다.
즉 return type은 bool 아님 객체타입 이 두 가지라고 생각하면 된다
[연산자 오버로딩 함수 선언 방법]
보통 왼편 오른편 둘 다 똑같은 클래스 객체가 오는 상황밖에 없을때는 지역함수만 구현해놔도 ㄱㅊ은데
만약 서로 다른 두 클래스 간 연산을 오버로딩할때는
교환법칙의 성립을 위해 전역함수 형태로도 오버라이딩 하는 수 밖에 없다.
이유는 아래
Point a,b,c; // 내 객체가 왼쪽 c = a+b; // 내 객체가 오른쪽 c = 3*a;오버로딩 선언 시 추가적으로 고려해야할 것은 객체가 왼편에 있는지 오른편에 있는지이다.
// pos1+pos2는 pos1.operator+(pos2) operator+(pos1,pos2) //이렇게 두 가지로 해석이 가능한데객체가 항상 왼편에 있는 경우면 그냥 클래스 내에 연산자 오버로딩함수를 구현하면 되는데
객체가 오른편에 올 상황도 있거나 오른편에 와도 정상적으로 작동하게 하려면
전역+friend 조합을 써야한다.
클래스 내 정의한 것은 묵시적으로 왼쪽 객체가 호출하는 상황에만 적용된다!
이게 왼쪽에 있으면
c = a + b; c = a.operator+(b);이렇게 변형되어 실행이 되는데
c = 3 * a; // 이런 경우는 3.operator*(a) // 이런게 안통한다따라서 이런 경우는 우리가 전역함수로 오버로딩함수를 만들어놓고 해당 클래스 내에 friend로 선언해놓는다.
이걸 전역함수로 만들면
Point operator*(int n,Point p){ Point retp; retp.x = p.x*n; retp.y = p.y*n; return retp; }이렇게 되는데 이것의 문제점은
해당 함수에서 해당 객체의 x, y 변수에 접근할 수 없다는 것이다
왜냐하면 해당 x,y변수들은 Point 클래스의 private 변수이기 때문이다
따라서 해당 전역함수가 클래스 내 private 변수에 접근할 수 있게끔
Point 클래스 안에서 friend로 선언부만 작성해놓는 것이다!
[반환형에서의 const 선언과 const 객체의 구별]
위의 후위증가 연산자 오버로딩이다.
const Point& operator++(int) { const Point temp(xpos, ypos); xpos++; ypos++; return temp; }여기서 함수 선언부에 const가 앞에 있으니 이건 반환형이 const 라는 뜻이다!
( const 함수이려면 const가 맨 뒤에 있어야함 )
따라서 반환하는 값이 Point 참조형이고, 이 참조자를 통해 반환할때 생기는 임시객체를 상수화시켜 내보낸다.
cf)
const 객체는 const 함수만 호출가능하다!
const 객체를 대상으로 참조자를 선언할때는 참조자도 const로 선언해야 한다.
'C++' 카테고리의 다른 글
[C++] 대입연산자 (assignment operator) (0) 2023.01.09 [c++] 연산자 오버로딩 (2) (cout cin 재정의하기) (0) 2023.01.08 [c++] 순수가상함수와 추상클래스 관련 특징 (0) 2023.01.06 [c++] 순수가상함수와 추상클래스 (0) 2023.01.06 [c++] 가상함수(virtual functions) (0) 2023.01.05