숏컷 코드
cpp
class Vec2 {
public:
double x, y;
Vec2 operator+(const Vec2& o) const { return {x+o.x, y+o.y}; }
Vec2& operator+=(const Vec2& o) { x+=o.x; y+=o.y; return *this; }
bool operator==(const Vec2& o) const { return x==o.x && y==o.y; }
// << 는 비멤버 friend
friend std::ostream& operator<<(std::ostream& os, const Vec2& v);
};
std::ostream& operator<<(std::ostream& os, const Vec2& v) {
return os << "(" << v.x << ", " << v.y << ")";
}문법
멤버 함수 vs 비멤버 함수 — 언제 무엇을 쓰나
operator+를 멤버 함수로 정의하면 왼쪽 피연산자는 항상 해당 클래스 타입이어야 합니다. 3 + vec처럼 왼쪽이 다른 타입인 경우를 지원하려면 비멤버 함수로 정의해야 합니다. <<는 왼쪽 피연산자가 ostream이므로 반드시 비멤버여야 합니다.
cpp
class Money {
int cents_;
public:
// 멤버: money * 3 → OK
Money operator*(int factor) const { return Money{cents_ * factor}; }
// 비멤버 필요: 3 * money
};
// 비멤버로 정의 — 교환 법칙 지원
Money operator*(int factor, const Money& m) { return m * factor; }
Money price{100};
auto a = price * 3; // ✅ 멤버 함수
auto b = 3 * price; // ✅ 비멤버 함수비교 연산자 — <=> (C++20 우주선 연산자)
C++20의 operator<=> 하나로 <, >, <=, >=, ==, != 여섯 개를 모두 생성할 수 있습니다.
cpp
#include <compare>
class Point {
int x_, y_;
public:
// C++20 — 한 번으로 6개 비교 연산자 모두 생성
auto operator<=>(const Point&) const = default;
bool operator==(const Point&) const = default;
};
Point a{1, 2}, b{1, 3};
bool lt = (a < b); // ✅ <=> 로 자동 생성
bool eq = (a == b); // ✅+= 정의 후 + 구현 — 중복 제거
+는 +=로 구현하면 로직을 한 곳에 유지할 수 있습니다.
cpp
class Vec2 {
public:
Vec2& operator+=(const Vec2& o) { // 핵심 구현
x += o.x; y += o.y;
return *this;
}
// + 는 += 로 구현 — 중복 없음
friend Vec2 operator+(Vec2 a, const Vec2& b) {
return a += b; // 복사 후 += 적용
}
double x, y;
};operator= — 복사 대입 연산자
cpp
class Buffer {
public:
Buffer& operator=(const Buffer& o) {
if (this == &o) return *this; // 자기 대입 방지
delete[] data_;
size_ = o.size_;
data_ = new char[size_];
std::memcpy(data_, o.data_, size_);
return *this; // *this 반환 필수 (a = b = c 체이닝)
}
private:
char* data_;
int size_;
};prefix vs postfix ++/-- — 반환 타입으로 구분
cpp
class Counter {
int val_ = 0;
public:
Counter& operator++() { ++val_; return *this; } // 전위: 참조 반환
Counter operator++(int) { // 후위: int 더미 인자
Counter tmp = *this; // 현재 값 저장
++val_;
return tmp; // 이전 값 반환 (값 복사)
}
};
Counter c;
++c; // 전위: 현재 객체 반환
c++; // 후위: 이전 값 복사본 반환 — 복사 비용 주의operator() — 함수 호출 연산자 (functor)
cpp
struct Multiplier {
int factor;
int operator()(int x) const { return x * factor; }
};
Multiplier times3{3};
std::cout << times3(10); // 30
// 알고리즘에 상태 있는 함수 객체 전달
std::vector<int> v{1, 2, 3, 4, 5};
std::transform(v.begin(), v.end(), v.begin(), times3);
// v = {3, 6, 9, 12, 15}operator[] — 첨자 연산자
cpp
class SafeArray {
int data_[10]{};
public:
int& operator[](int i) { return data_[i]; } // 수정 가능
int operator[](int i) const { return data_[i]; } // const 버전
};
SafeArray a;
a[3] = 42; // operator[](3) 호출 — 참조 반환이라 대입 가능
std::cout << a[3]; // 42변환 연산자
cpp
class Celsius {
double temp_;
public:
explicit Celsius(double t) : temp_{t} {}
explicit operator double() const { return temp_; } // 명시적 변환
operator std::string() const { return std::to_string(temp_) + "°C"; }
};
Celsius c{36.5};
double d = static_cast<double>(c); // explicit — 명시적 캐스트 필요
std::string s = c; // non-explicit — 암시적 변환 허용체크포인트
| 상황 | 적합한 선택 |
|---|---|
| 왼쪽 피연산자가 항상 같은 타입 | 멤버 함수 |
<<, >> 스트림 연산자 | 비멤버 friend 함수 |
| 교환 법칙 지원 (3 + val) | 비멤버 함수 |
| 6개 비교 연산자 자동 생성 | C++20 operator<=> |
복합 대입 (+=) | 멤버 함수, *this 반환 |
| 복사 대입 | operator=, 자기 대입 확인, *this 반환 |
전위 ++ | T& operator++() — 참조 반환 |
후위 ++ | T operator++(int) — 값 반환, int 더미 인자 |
| 상태 있는 함수 객체 | operator() (functor) |
| 인덱스 접근 | operator[], const/non-const 쌍 |
| 타입 변환 | explicit operator T() |
주의할 점
연산자 오버로딩은 기존 연산자의 의미와 크게 다르게 정의하면 코드 읽기가 어려워집니다. 직관에서 벗어나는 오버로딩은 지양합니다.
cpp
// ❌ + 연산자로 삭제? 직관에 반함
class List {
List operator+(int index) {
// index번째 원소 삭제 -- 매우 혼란
}
};
// ✅ + 는 추가/합산처럼 직관적 의미로만
class Vector3 {
Vector3 operator+(const Vector3& o) const { return {x+o.x, y+o.y, z+o.z}; }
};참고 링크
1 sources