C++의 연산자 오버로딩(Operator Overloading)은 사용자 정의 타입(클래스, 구조체)에 대해 표준 연산자(+, -, *, << 등)의 동작을 재정의하는 기능이다.
이를 통해 객체를 기본 자료형처럼 직관적으로 다룰 수 있다.
산술 연산자 오버로딩 (+)
좌표를 나타내는 Point 클래스에서 두 객체를 더하는 연산자를 정의한다.
#include <iostream>
class Point {
private:
int x, y;
public:
Point(int x = 0, int y = 0) : x(x), y(y) {}
// + 연산자 오버로딩 (멤버 함수 방식)
Point operator+(const Point& other) const {
return Point(this->x + other.x, this->y + other.y);
}
void display() const {
std::cout << "(" << x << ", " << y << ")" << std::endl;
}
};
int main() {
Point p1(10, 20);
Point p2(5, 5);
// 객체 간의 직관적인 연산 가능
Point p3 = p1 + p2;
p3.display(); // (15, 25)
return 0;
}
출력 연산자 오버로딩 (<<)
std::cout을 통해 객체를 즉시 출력할 수 있도록 << 연산자를 오버로딩한다.
이 연산자는 대개 friend 함수로 정의한다.
#include <iostream>
class Point {
int x, y;
public:
Point(int x, int y) : x(x), y(y) {}
// 전역 함수 방식의 오버로딩 (friend 선언으로 private 멤버 접근 허용)
friend std::ostream& operator<<(std::ostream& os, const Point& p) {
os << "Point(" << p.x << ", " << p.y << ")";
return os;
}
};
int main() {
Point p(10, 20);
// 함수 호출 대신 직관적인 출력 가능
std::cout << "Result: " << p << std::endl;
return 0;
}
주요 규칙 및 주의사항
- 우선순위 유지: 연산자의 원래 우선순위와 결합 법칙은 바뀌지 않는다.
- 피연산자 개수: 기존 연산자가 가진 피연산자의 개수를 변경할 수 없다.
(예: 이항 연산자를 삼항으로 바꿀 수 없음) - 새로운 연산자 생성 불가:
**나<>와 같이 기존에 없는 연산자를 새로 만들 수는 없다. - 직관성 유지:
+연산자가 뺄셈을 수행하게 만드는 등 연산자의 본래 의미를 훼손하는 오버로딩은 지양해야 한다.
P.S
연산자 오버로딩은 코드의 가독성과 표현력을 높여주는 강력한 기능이다.
하지만 과도하거나 부적절한 사용은 코드의 모호성을 높일 수 있으므로, 연산이 자연스러운 상황에만 제한적으로 적용하는 설계적 안목이 필요하는 것 같다.