C++ 오버로딩 마스터하기: 함수 & 연산자 오버로딩 완전 정복
C++은 동일한 범위에서 함수 이름이나 연산자에 대해 둘 이상의 정의를 지정할 수 있게 하며, 이를 각각 함수 오버로딩(function overloading)과 연산자 오버로딩(operator overloading)이라 부릅니다.
오버로드된 선언은 동일한 범위에서 이전에 선언된 선언과 같은 이름으로 선언되지만, 인자가 다르며 당연히 정의(구현)도 다릅니다.
오버로드된 함수나 연산자를 호출하면, 컴파일러는 함수나 연산자 호출에 사용된 인자 타입을 정의에 지정된 매개변수 타입과 비교해 가장 적절한 정의를 결정합니다. 가장 적절한 오버로드 함수나 연산자를 선택하는 과정을 오버로드 해상도(overload resolution)라 부릅니다.
C++ 함수 오버로딩
동일한 범위에서 같은 함수 이름에 대해 여러 정의를 가질 수 있습니다. 함수 정의는 인자 목록의 타입과/또는 개수에서 서로 달라야 합니다. 반환 타입만 다른 함수 선언은 오버로드할 수 없습니다.
같은 함수 print()를 사용해 다른 데이터 타입을 출력하는 예제:
Live Demo
#include <iostream>
using namespace std;
class printData {
public:
void print(int i) {
cout << "Printing int: " << i << endl;
}
void print(double f) {
cout << "Printing float: " << f << endl;
}
void print(char* c) {
cout << "Printing character: " << c << endl;
}
};
int main(void) {
printData pd;
// 정수 출력 호출
pd.print(5);
// 실수 출력 호출
pd.print(500.263);
// 문자 출력 호출
pd.print("Hello C++");
return 0;
}
위 코드를 컴파일하고 실행하면:
Printing int: 5
Printing float: 500.263
Printing character: Hello C++
C++ 연산자 오버로딩
C++에서 사용 가능한 대부분의 내장 연산자를 재정의하거나 오버로드할 수 있습니다. 따라서 프로그래머는 사용자 정의 타입에도 연산자를 사용할 수 있습니다.
오버로드된 연산자는 특수 이름을 가진 함수입니다: 키워드 "operator" 뒤에 정의되는 연산자 기호가 옵니다. 다른 함수처럼 오버로드된 연산자도 반환 타입과 매개변수 목록을 가집니다.
Box operator+(const Box&);
두 Box 객체를 더해 최종 Box 객체를 반환하는 덧셈 연산자를 선언합니다. 대부분의 오버로드 연산자는 일반 비멤버 함수나 클래스 멤버 함수로 정의할 수 있습니다. 위 함수를 클래스의 비멤버 함수로 정의하면 각 피연산자에 대해 두 인자를 전달해야 합니다.
Box operator+(const Box&, const Box&);
멤버 함수를 사용한 연산자 오버로딩 개념 예제. 여기서 인자로 객체가 전달되며, 이 객체의 속성은 this 객체를 통해 접근합니다. 이 연산자를 호출하는 객체는 this 연산자로 접근할 수 있습니다.
Live Demo
#include <iostream>
using namespace std;
class Box {
public:
double getVolume(void) {
return length * breadth * height;
}
void setLength(double len) { length = len; }
void setBreadth(double bre) { breadth = bre; }
void setHeight(double hei) { height = hei; }
// + 연산자 오버로드: 두 Box 객체 더하기
Box operator+(const Box& b) {
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}
private:
double length;
double breadth;
double height;
};
int main() {
Box Box1, Box2, Box3;
double volume = 0.0;
// Box1 사양
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// Box2 사양
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// Box1 부피
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume << endl;
// Box2 부피
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume << endl;
// 두 객체 더하기
Box3 = Box1 + Box2;
// Box3 부피
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume << endl;
return 0;
}
위 코드를 컴파일하고 실행하면:
Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400
오버로드 가능/불가능 연산자
오버로드할 수 있는 연산자 목록:
| + | - | * | / | % | ^ |
| & | | | ~ | ! | , | = |
| < | > | <= | >= | ++ | -- |
| << | >> | == | != | && | || |
| += | -= | /= | %= | ^= | &= |
| |= | *= | <<= | >>= | [] | () |
| -> | ->* | new | new [] | delete | delete [] |
오버로드할 수 없는 연산자 목록:
연산자 오버로딩 예제
개념 이해를 돕기 위한 다양한 연산자 오버로딩 예제:
| 번호 | 연산자 및 예제 |
| 1 | 단항 연산자 오버로딩 |
| 2 | 이항 연산자 오버로딩 |
| 3 | 관계 연산자 오버로딩 |
| 4 | 입출력 연산자 오버로딩 |
| 5 | ++ 및 -- 연산자 오버로딩 |
| 6 | 대입 연산자 오버로딩 |
| 7 | 함수 호출 () 연산자 오버로딩 |
| 8 | 첨자 [] 연산자 오버로딩 |
| 9 | 클래스 멤버 접근 -> 연산자 오버로딩 |