연산자 재정의 (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 |
댓글