함수 오버로딩
- 이름은 같지만 매개변수의 타입 혹은 개수가 다른 함수
- 반환형이 다른 것은 인정되지 않음
- bool과 string으로만 오버로딩 할 경우 char형 배열/포인터는 string이 아닌 bool형으로 판단
- 코드
#include <iostream>
#include <string>
using namespace std;
void func(const int& i) { cout << "func(const int& i)" << endl; }
void func(const bool& bArg) { cout << "func(const bool &bArg)" << endl; }
void func(const string& s) { cout << "func(const string& s)" << endl; }
int main() {
func(1);
func(true);
func("abc");
func(string("abc"));
return 0;
}
- 실행 결과
func(const int& i)
func(const bool &bArg)
func(const bool &bArg)
func(const string& s)
연산자 오버로딩
- 디폴트 대입 연산자
- 디폴트 복사 생성자와 마찬가지로 얕은 복사를 하므로 주의
- +, -, *, /의 경우 a = b + c + b 등의 식을 계산할때 상식적인 의미 전달을 위해 일반적으로는 반환형을 레퍼런스로 선언하지 않음
- 자기 자신을 리턴하지 않는 연산자(+, -, *, /)는 외부 함수로 선언하는 것이 원칙
- 코드
#include <iostream>
#include <string>
using namespace std;
class Test {
private:
int i = 0;
public:
Test(const int& i) : i(i){};
Test(const Test& t) : i(t.i) {}
~Test() = default;
Test& operator+=(const Test& t) {
(*this) = (*this) + t;
return *this;
}
Test& operator-=(const Test& t) {
(*this) = (*this) - t;
return *this;
}
Test& operator*=(const Test& t) {
(*this) = (*this) * t;
return *this;
}
Test& operator/=(const Test& t) {
(*this) = (*this) / t;
return *this;
}
Test& operator=(const Test& t) {
this->i = t.i;
return *this;
}
Test& operator++() {
*this += 1;
return *this;
}
Test operator++(int) {
Test t(*this);
*this += 1;
return t;
}
Test& operator--() {
*this -= 1;
return *this;
}
Test operator--(int) {
Test t(*this);
*this -= 1;
return t;
}
bool operator==(const Test& t) const { return this->i == t.i; }
friend Test operator+(const Test& t1, const Test& t2);
friend Test operator-(const Test& t1, const Test& t2);
friend Test operator*(const Test& t1, const Test& t2);
friend Test operator/(const Test& t1, const Test& t2);
friend ostream& operator<<(ostream& os, const Test& t);
};
Test operator+(const Test& t1, const Test& t2) { return Test(t1.i + t2.i); }
Test operator-(const Test& t1, const Test& t2) { return Test(t1.i - t2.i); }
Test operator*(const Test& t1, const Test& t2) { return Test(t1.i * t2.i); }
Test operator/(const Test& t1, const Test& t2) { return Test(t1.i / t2.i); }
ostream& operator<<(ostream& os, const Test& t) {
os << t.i;
return os;
}
class Test2 {
private:
string s = "";
public:
Test2(const string& s) : s(s) {}
char& operator[](const int index) { return this->s.at(index); }
};
class Integer {
private:
int i = 0;
public:
Integer(const int& i) : i(i){};
Integer(const Integer& t) : i(t.i) {}
~Integer() = default;
operator int() { return this->i; }
};
int main() {
Test t1(1);
Test t2(2);
Test t3(3);
cout << t1 + t2 << endl;
cout << t1 - t2 << endl;
cout << t1 * t2 << endl;
cout << t1 / t2 << endl;
cout << (t1 += t2) << endl;
cout << (t1 -= t2) << endl;
cout << (t1 *= t2) << endl;
cout << (t1 /= t2) << endl;
cout << (t1 = t2) << endl;
cout << (t1 == t2) << endl;
cout << (t1 == t3) << endl;
cout << t3++ << endl;
cout << ++t3 << endl;
cout << t3-- << endl;
cout << --t3 << endl;
Test2 t4("abc");
cout << t4[1] << endl;
Integer i = 1;
int ii = i + 2;
cout << i << ", " << ii << endl;
return 0;
}
- 실행 결과
3
-1
2
0
3
1
2
1
2
1
0
3
5
5
3
b
1, 3
함수 오버라이딩
- 기반 클래스의 함수를 파생 클래스가 재정의
- 오버라이드가 안되는 실수를 맞기 위해 오버라이딩된 함수에 override 키워드를 통해 명시적으로 선언해주는 것을 권장
- 코드
#include <iostream>
using namespace std;
using namespace std;
class Base {
public:
virtual void func() { cout << "Base()::func" << endl; }
};
class Derived : public Base {
public:
virtual void func() override { cout << "Derived()::func" << endl; }
};
int main(void) {
Base b1;
b1.func();
cout << "------" << endl;
Derived d;
d.func();
cout << "------" << endl;
Base& b2 = d;
b2.func();
return 0;
}
- 실행 결과
Base()::func
------
Derived()::func
------
Derived()::func