3 분 소요

오버로딩(Overloading)이란?

오버로딩은 같은 이름을 가진 함수나 연산자를 다양한 매개변수로 정의하는 것을 의미합니다.
C++에서는 연산자 오버로딩을 통해 사용자 정의 데이터 타입에 대한 연산자를 재정의할 수 있습니다.

연산자 오버로딩(Operator Overloading)

연산자 오버로딩은 사용자 정의 데이터 타입에 대한 연산자를 재정의하는 것을 의미합니다.
C++에서는 다음과 같은 연산자를 오버로딩할 수 있습니다.

산술 연산자

예시에서는 return type이 float지만, 다른 타입으로도 가능합니다.

Foo.hpp
class Foo {
    private:
        float data;
    public:
        float operator+(const Foo& rhs) const;
        float operator-(const Foo& rhs) const;
        float operator*(const Foo& rhs) const;
        float operator/(const Foo& rhs) const;
        // rhs는 right hand side의 약자로, 오른쪽 피연산자를 의미합니다.
};
Foo.cpp
float Foo::operator+(const Foo& rhs) const {
    return (float) (this->data + rhs.data);
}
float Foo::operator-(const Foo& rhs) const {
    return (float) (this->data - rhs.data);
}
float Foo::operator*(const Foo& rhs) const {
    return (float) (this->data * rhs.data);
}
float Foo::operator/(const Foo& rhs) const {
    return (float) (this->data / rhs.data);
}

관계 연산자

Foo.hpp
class Foo {
    private:
        float data;
    public:
        bool operator==(const Foo& rhs) const;
        bool operator!=(const Foo& rhs) const;
        bool operator<(const Foo& rhs) const;
        bool operator>(const Foo& rhs) const;
        bool operator<=(const Foo& rhs) const;
        bool operator>=(const Foo& rhs) const;
};
Foo.cpp
bool Foo::operator==(const Foo& rhs) const {
    return this->data == rhs.data;
}
bool Foo::operator!=(const Foo& rhs) const {
    return this->data != rhs.data;
}
bool Foo::operator<(const Foo& rhs) const {
    return this->data < rhs.data;
}
...

대입 연산자

Foo.hpp
class Foo {
    private:
        float data;
    public:
        Foo& operator=(const Foo& rhs);
};
Foo.cpp
Foo& Foo::operator=(const Foo& rhs) {
    this->data = rhs.data;
    return *this;
}

증감 연산자

Foo.hpp
class Foo {
    private:
        float data;
    public:
        Foo& operator++(); // 전위 증가 연산자
        Foo operator++(int); // 후위 증가 연산자
        Foo& operator--(); // 전위 감소 연산자
        Foo operator--(int); // 후위 감소 연산자
};
Foo.cpp
Foo& Foo::operator++() {
    this->data++;
    return *this;
}
Foo Foo::operator++(int) {
    Foo temp = *this;
    this->data++;
    return temp;
}
Foo& Foo::operator--() {
    this->data--;
    return *this;
}
Foo Foo::operator--(int) {
    Foo temp = *this;
    this->data--;
    return temp;
}

함수 호출 연산자

Foo.hpp
class Foo {
    private:
        float data;
    public:
        float operator()(int a, int b);
};
Foo.cpp
float Foo::operator()(int a, int b) {
    return (float) (a + b);
}

배열 연산자

Foo.hpp
class Foo {
    private:
        float data[3];
    public:
        float& operator[](int index);
};
Foo.cpp
float& Foo::operator[](int index) {
    return data[index];
}

입출력 연산자

Foo.hpp
class Foo {
    private:
        float data;
    public:
        friend std::ostream& operator<<(std::ostream& os, const Foo& foo);
        friend std::istream& operator>>(std::istream& is, Foo& foo);
};
Foo.cpp
std::ostream& operator<<(std::ostream& os, const Foo& foo) {
    os << foo.data;
    return os;
}
std::istream& operator>>(std::istream& is, Foo& foo) {
    is >> foo.data;
    return is;
}

연산자 오버로딩의 장점

  • 사용자 정의 데이터 타입에 대한 연산자를 재정의할 수 있어, 코드의 가독성이 높아집니다.
  • 연산자 오버로딩을 통해 사용자 정의 데이터 타입에 대한 연산자를 사용할 수 있습니다.

& 사용 이유

참조자로 반환하는 이유는 여러 가지가 있습니다. 가장 일반적인 이유 중 하나는 연속적인 대입 연산을 가능하게 하는 것입니다. 대입 연산자를 오버로딩할 때, 반환 값을 참조자로 설정하면 다음과 같은 효과가 있습니다:

  1. 연속적인 대입: 반환 값을 참조자로 설정하면 대입 연산자를 연속적으로 사용할 수 있습니다. 예를 들어, a = b = c와 같은 코드에서 b = c가 먼저 실행되고 그 결과를 a에 대입할 수 있습니다.

  2. 효율성: 임시 객체(temporary object)의 생성을 줄일 수 있습니다. 참조자를 반환하면 객체의 복사를 피할 수 있으며, 이는 성능에 긍정적인 영향을 미칩니다.

  3. 일관성: C++의 일반적인 사용 패턴과 일치시킵니다. STL(Standard Template Library)과 같은 C++ 라이브러리는 연산자들을 일반적으로 참조자를 반환하여 연속적인 연산을 지원합니다.

따라서 대입 연산자를 오버로딩할 때 반환 값을 참조자로 설정하는 것은 코드의 가독성, 효율성 및 일관성을 유지하는 데 도움이 됩니다.

main.cpp
#include "Foo.hpp"

int main() {
    Foo a, b, c;
    a = b = c;
    return 0;
}
Foo.hpp
class Foo {
    private:
        float data;
    public:
        Foo& operator=(const Foo& rhs);
        Foo operator=(const Foo& rhs);
};
Foo.cpp
Foo& Foo::operator=(const Foo& rhs) {
    this->data = rhs.data;
    return *this;
}
Foo Foo::operator=(const Foo& rhs) {
    this->data = rhs.data;
    return *this;
}

카테고리:

업데이트: