3 분 소요

함수 오버로딩

  • 이름은 같지만 매개변수의 타입 혹은 개수가 다른 함수
  • 반환형이 다른 것은 인정되지 않음
  • 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