연산자 오버로딩

윤형찬·2020년 11월 3일
1

C++

목록 보기
10/10
post-thumbnail

산술 연산자 오버로딩 하기

  • int나 double같은 기본적인 자료형들은 자기들 사이의 산술연산자들이 모두 정의가 되어있어서 편하게 코딩할 수 있다
  • 사용자 정의 자료형 끼리도 산술 연산자를 정의할 수 있다.
  • 연산자의 우선순위는 항상 그대로다.
    (내가 만든 곱하기 연산자는 내가만든 더하기 연산자보다 항상 우선)

예제

class Cents
{
private:
    int m_cents;
    
public:
    Cents(int cents = 0) { m_cents = cents; }
    int getCents() const { return m_cents; }
    int& getCents() { return m_cents; }
    
    // friend로 사용해도 되고, 멤버 직접받기도 가능하다 
    // 멤버 직접 사용을 위해 파라미터를 하나 줄이고 this를 사용한다.
    Cents operator + (const Cents& c2)
    {
        return Cents(this->m_cents + c2.getCents());
    }
};

int main()
{
    Cents cents1(6);
    Cents cents2(8);
    
    cout << (cents1 + cents2 + Cents(6) + Cents(10)).getCents() << endl;
    
    return 0;
}


입출력 연산자 오버로딩 하기

사용 예제

#include <iostream>
#include <fstream>
using namespace std;

class Point
{
private:
    double m_x, m_y, m_z;
    
public:
    Point(double x = 0.0, double y = 0.0, double z = 0.0)
    : m_x(x), m_y(y), m_z(z)
    {}
    
    double getX() { return m_x; }
    double getY() { return m_y; }
    double getz() { return m_z; }
    
    friend std::ostream& operator << (std::ostream &out, const Point &point)
    {
        out << "( " << point.m_x << " " << point.m_y << " " << point.m_z << " )";
        return out;
    }
    
    friend std::istream& operator >> (std::istream &in, Point &point)
    {
        in >> point.m_x >> point.m_y >> point.m_z;
        
        return in;
    }
};
int main()
{
    ofstream of("/Users/hyengchan/Documents/dev/cpp_self_study/Chapter9/Chap9_2_io_operator_overloading/out.txt");
    
    Point p1(0.0, 1.2, 6.2), p2(3.5, 12.2, 6.9);
    
    cout << p1 << " " << p2;
    of << p1 << " " << p2 << endl;
    
    of.close();
    
    Point p3, p4;
    
    cin >> p3 >> p4;
    cout << p3 << " " << p4;
    
    
    return 0;
}


단항 연산자 오버로딩 하기

사용 예제

class Cents
{
private:
    int m_cents;
    
public:
    Cents(int cents = 0) { m_cents = cents; }
    int getCents() const { return m_cents; }
    int& getCents() { return m_cents; }
    
    Cents operator - () const
    {
        return Cents(-m_cents);
    }
    
    bool operator ! () const
    {
        // 돈이 없을때만 true 출력하게 한다
        return (m_cents == 0 ) ? true : false;
    }
    
    friend std::ostream& operator << (std::ostream &out, const Cents &cents)
    {
        out << cents.m_cents;
        return out;
    }
};

int main()
{
    Cents cents1(6);
    Cents cents2(0);
    
    cout << cents1 << endl;
    cout << -cents1 << endl;
    cout << -Cents(-10) << endl;
    
    cout << !cents1 << " " << !cents2 << endl;
    
    return 0;
}


비교연산자 오버로딩 하기

== 오버로딩 예제

class Cents
{
private:
    int m_cents;
    
public:
    Cents(int cents = 0) { m_cents = cents; }
    int getCents() const { return m_cents; }
    int& getCents() { return m_cents; }
    
    friend bool operator == (const Cents &c1, const Cents &c2)
    {
        return c1.m_cents == c2.m_cents;
    }
    
    friend std::ostream& operator << (std::ostream &out, const Cents &cents)
    {
        out << cents.m_cents;
        return out;
    }
};

int main()
{
    Cents cents1(6);
    Cents cents2(6);
    
    if(cents1 == cents2)
        cout << "Equal " <<endl;
    
    return 0;
}

sorting(크기 비교) 예제

#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
using namespace std;

class Cents
{
private:
    int m_cents;
    
public:
    Cents(int cents = 0) { m_cents = cents; }
    int getCents() const { return m_cents; }
    int& getCents() { return m_cents; }
    
    // sort 할때는 > 말고 < 로 만들어 줘야함.
    // return 부등호를 >로 바꾸면 역순 정렬한다.
    friend bool operator < (const Cents &c1, const Cents &c2)
    {
        return c1.m_cents < c2.m_cents;
    }
    
    friend std::ostream& operator << (std::ostream &out, const Cents &cents)
    {
        out << cents.m_cents;
        return out;
    }
};

int main()
{
    vector<Cents> arr(20);
    for(unsigned int i = 0; i < 20; ++i)
        arr[i].getCents() = i;
    
    std::random_device rd;
    std::mt19937 g(rd());
    std::shuffle(arr.begin(), arr.end(),g);
    
    for(auto &e : arr)
        cout << e << " ";
    cout << endl;
    
    // 크기 비교를 위해 비교 연산자를 만들어줘야함
    std::sort(begin(arr), end(arr));
    
    for (auto &e : arr)
        cout << e << " ";
    cout << endl;
    
    return 0;
}


증감 연산자 오버로딩 하기

예제

class Digit
{
private:
    int m_digit;
public:
    Digit(int digit = 0) : m_digit(digit) {}
    
    // 전위형
    Digit & operator ++ ()
    {
        ++m_digit;
        // 자기 자신을 리턴한다.
        return *this;
    }
    
    // 후위형은 parameter에 dummy형이 아무거나 들어가야함
    Digit operator ++ (int)
    {
        Digit temp(m_digit);
        ++(*this);
        return temp;
    }
    
    friend std::ostream& operator << (std::ostream &out, const Digit &d)
    {
        out << d.m_digit;
        return out;
    }
};

int main()
{
    Digit d(5);
    
    cout << ++d << endl;
    cout << d << endl;
    
    cout << d++ << endl;
    cout << d << endl;
    
    return 0;
}


첨자 연산자 오버로딩 하기

사용 예제

using namespace std;

class IntList
{
private:
    int m_list[10];
    
public:
    int & operator [] (const int index)
    {
        assert(index >= 0);
        assert(index < 10);
        return m_list[index];
    }
};

int main()
{
    IntList my_list;      
    my_list[3] = 10;
    cout << my_list[3] << endl;
    
    return 0;
}


괄호 연산자 오버로딩과 함수 객체

  • 괄호 연산자는 특징상 함수를 호출할 때 사용하는 괄호랄 똑같다.
  • 괄호 연산자를 오버로딩 하면 마치 함수가 객체인것 처럼(functor) 사용가능

사용 예제

class Accumulator
{
private:
    int m_counter = 0;
    
public:
    int operator()(int i) { return (m_counter += i ); }
};

int main() {
    Accumulator acc;
    cout << acc(10) << endl;
    cout << acc(20) << endl;
    
    return 0;
}


형변환(static_cast)을 오버로딩 하기

예제

class Cents
{
private:
    int m_cents;
    
public:
    Cents(int cents = 0) { m_cents = cents; }
    int getCents() const { return m_cents; }
    void settCents(int cents) { m_cents = cents; }
    
    // 형변환 오버로딩
    operator int()
    {
        return m_cents;
    }
};

class Dollar
{
private:
    int m_dollars = 0;
    
public:
    Dollar(const int& input) : m_dollars(input) {}
    
    operator Cents()
    {
        return Cents(m_dollars * 100);
    }
};

void printInt(const int &value)
{
    cout << value << endl;
}

int main() {
    Cents cents(7);
    printInt(cents);
    
    Dollar dol(2);
    Cents cents2 = dol;
    printInt(cents2);
    
    return 0;
}


대입 연산자 오버로딩, 깊은 복사, 얕은 복사

  • 동적 할당된 메모리에 대한 포인터 변수를 멤버로써 가지고 있는 클래스의 경우 복사를 하거나 대입을 할 때 깊은 복사냐 얕은 복사냐 하는 문제로 인해서 대입연산자 오버로딩 혹은 복사 생성자 구현이 좀 까다로워 진다.

예제는 github 9_11 확인



이니셜 라이저 리스트 { }

  • 클래스같은 사용자 정의 자료형에서 생성자나 대입연산자를 만들때 편하게 사용할 수 있다.

예제는 github 9_12 확인

profile
https://github.com/velmash

1개의 댓글

comment-user-thumbnail
2020년 12월 3일

잘 정리해두셨군요^^
좋은 글 잘 봤습니다.

답글 달기