C++에서는 동일한 이름의 함수를 여러 개 정의할 수 있습니다.
그 이유는 C언어는 함수 이름으로만 함수를 구분하지만, C++은 함수 이름과 매개변수 타입 정보를 함께 사용해 구분하기 때문입니다.
이런 식으로 함수 이름 구분을 위해 내부적으로 고유한 이름을 부여하는 것을 네임 맹글링(Name Mangling) 이라고 합니다.
// 목적 : 함수 오버로딩의 개념을 매개변수 타입이 다른 경우로 이해하기 #include <iostream> using namespace std; void print(int a) { cout << "정수 출력: " << a << endl; } void print(double a) { cout << "실수 출력: " << a << endl; } int main() { print(10); // 정수 출력 print(3.14); // 실수 출력 return 0; } // 출력결과: // 정수 출력: 10 // 실수 출력: 3.14
// 목적: 디폴트 매개변수로 인해 호출 형태가 중복되는 경우 #include <iostream> using namespace std; void display(int a, int b = 5) { cout << a << ", " << b << endl; } void display(int a) { cout << a << endl; } int main() { // display(10); // 디폴트 매개변수로 인해 두 함수 모두 호출 가능하므로 애매모호 return 0; } /* 출력결과 (컴파일 에러): error: call of overloaded 'display(int)' is ambiguous */
// 목적: 매개변수의 타입이 포인터와 배열일 때 애매모호성 발생 예시 #include <iostream> using namespace std; void print(int* arr) { cout << "포인터 호출됨" << endl; } void print(int arr[]) { cout << "배열 호출됨" << endl; } int main() { int data[3] = { 1, 2, 3 }; // print(data); // 포인터와 배열은 같은 타입으로 취급되어 애매모호 return 0; } /* 출력결과 (컴파일 에러): error: redefinition of 'void print(int*)' 배열과 포인터는 매개변수로 구분되지 않음 */
// 목적: 표준 변환이 불가능하면 사용자 정의 변환이 호출됨을 학습 #include <iostream> using namespace std; class MyNumber { public: operator int() const { return 42; } }; void print(int a) { cout << "int 타입 호출됨, 값: " << a << endl; } void print(double a) { cout << "double 타입 호출됨, 값: " << a << endl; } int main() { MyNumber num; print(num); // 사용자 정의 변환을 통해 MyNumber->int로 변환됨 return 0; } // 출력결과: // int 타입 호출됨, 값: 42
함수 오버로딩이 되려면, 호출되는 함수가 분명해야 한다. 호출 시점에서 호출할 함수가 명확하지 않으면 컴파일러는 애매모호성 오류를 발생시킨다.
컴파일러는 최대한 변환할 수 있는 함수를 찾으려고 합니다. C++에서는 아래와 같은 명확한 우선순위 규칙에 따라 호출할 함수를 결정한다.
정확한 매칭 -> 타입 승격 변환 -> 표준 타입 변환 -> 사용자 정의 타입 변환
1. 정확한 매개변수 타입 일치 : 호출 인자 타입과 매개변수 타입이 정확히 일치하는 경우
2. 타입 승격 변환 : 값이 손실되지 않는 방향으로 변환하는 것을 승격이라한다.
ex) char or short -> int , float -> double , bool -> int
3. 표준 타입 변환 : 승격보다는 조금 더 광범위하다. 값 손실이 발생하는 경우도 있다. ex) int -> double , double -> int , double -> float
4. 사용자 정의 타입 변환 : 클래스 타입의 변환 함수나 생성자 등을 통해 이뤄지는 변환이다.
기존 연산자(+ , - , * , / 등)에 사용자 정의 타입에 대한 새로운 의미를 부여하는 것
#include <iostream> using namespace std; class Complex { private: double real, imag; public: Complex(double r = 0, double i = 0) : real(r), imag(i) {} // 멤버 함수로 연산자 오버로딩 Complex operator+(const Complex& other) const { return Complex(real + other.real, imag + other.imag); } void print() const { cout << real << " + " << imag << "i" << endl; } }; int main() { Complex c1(3, 4); Complex c2(1, 2); Complex c3 = c1 + c2; // c1.operator+(c2) 호출 c3.print(); // 4 + 6i }
산술연산자
#include <iostream> using namespace std; class Number { private: int value; public: Number(int v = 0) : value(v) {} // 덧셈 Number operator+(const Number& other) const { return Number(value + other.value); } // 뺄셈 Number operator-(const Number& other) const { return Number(value - other.value); } // 곱셈 Number operator*(const Number& other) const { return Number(value * other.value); } // 나눗셈 Number operator/(const Number& other) const { if (other.value == 0) { throw runtime_error("Division by zero"); } return Number(value / other.value); } // 나머지 Number operator%(const Number& other) const { return Number(value % other.value); } // 단항 마이너스 Number operator-() const { return Number(-value); } // 단항 플러스 Number operator+() const { return Number(+value); } int getValue() const { return value; } }; int main() { Number n1(10); Number n2(3); Number sum = n1 + n2; // 13 Number diff = n1 - n2; // 7 Number prod = n1 * n2; // 30 Number quot = n1 / n2; // 3 Number rem = n1 % n2; // 1 Number neg = -n1; // -10 }
- 복합 대입 연산자, 증감 연산자, 비교 연산자, 논리 연산자, 비트 연산자, 배열 접근 연산자 [] 등 사용할수있다.