본문 바로가기
C++ STL/Part 01 C++ 문법

1장 연산자 오버로딩

by 노오오오오옹 2021. 6. 17.

1-1. 연산자 오버로딩이란

C++에서 제공하는 기본 타입이 아닌 클래스 타입, 즉 사용자 정의 타입에서도 연산자를 사용할 수 있게 만든 문법

n1 + n2; // + 연산자 오버로딩
n1 * n2; // * 연산자 오버로딩
n2 = n1; // = 연산자 

 

1-2. 연산자 오버로딩 정의 및 사용

class Point
{
    ...
    
    const Point operator+(const Point& p)
    {
    	Point pt;
        pt.x = this->x + p.x;
        pt.y = this->y + p.y;
        
        return pt;
    }
};

int main()
{
    Point p1(2,3);
    Point p2(2,4);
    Point p3;
    
    p3 = p1 + p2; // p1.operator+(p2)
}

 

1-3. 단항 연산자 오버로딩

오버로딩이 가능한 연산자 : !, &, ~, *, +, -, ++, --

 

  • ++ 연산자 오버로딩

전위 연산자(++n), 후위 연산자(n++)이 있다.

class Point
{
    ...
    
    const Point& operator++() // 전위 연산자
    {
    	++x;
        ++y;
        
        return *this;
    }
    
    const Point operator++(int) // 후위 연산자
    {
    	Point p(x, y);
        ++x; // 내부 구현이기 때문에 ++도 상관없다!
        ++y;
        
        return pt; // 값은 계산안한 값을 반환
    }
};

int main()
{
    Point p1(2,3);
    Point p2(2,3);
    Point res;
    
    res = ++p1; // p1.opeartor++() 
    // res: (3,4)
    // p1: (3,4)
    
    res = p2++; // p2.operator++(0)
    // res: (2,3)
    // p2: (3,4)
    
}

 

  • -- 연산자 오버로딩

++연산자와 같다.

class Point
{
    ...
    
    const Point& operator--() // 전위 연산자
    {
    	--x;
        --y;
        
        return *this;
    }
    
    const Point operator--(int) // 후위 연산자
    {
    	Point p(x, y);
        --x; // 내부 구현이기 때문에 --도 상관없다!
        --y;
        
        return pt; // 값은 계산안한 값을 반환
    }
};

int main()
{
    Point p1(2,3);
    Point p2(2,3);
    Point res;
    
    res = --p1; // p1.opeartor--() 
    // res: (1,2)
    // p1: (1,2)
    
    res = p2--; // p2.operator--(0)
    // res: (2,3)
    // p2: (1,2)
    
}

 

1-4. 이항 연산자 오버로딩

가능한 연산자 : +, -, *, /, ==, !=, <, <=

  • == 연산자 오버로딩
class Point
{
    ...
    
    bool opeartor==(const Point& p) const
    {
        return this->x == p.x && this->y == p.y;
    }
};

int main()
{
    Point p1(2,3);
    Point p2(2,3);
    Point p3(3,4);
    
    if(p1==p2) // p1.operator==(p2) // return true
    {
        ...
    }
    
    if(p1==p3) // return false
    {
        ...
    }
}

 

  • != 연산자 오버로딩
class Point
{
    ...
    
    bool opeartor==(const Point& p) const
    {
        return this->x == p.x && this->y == p.y;
    }
    
    bool operator!=(const Point& p) const
    {
        return !(*this == p);
    }
};

 

1-5 전역 함수를 이용한 연산자 오버로딩

  • 멤버 함수를 이용한 연산자 오버로딩(위의 모습)
  • 전역 함수를 이용한 연산자 오버로딩
// 기존방식
p1 + p2; // p1.opeator+(p2)

// 전역함수 연산자 오버로딩(operator(n1, n2))
k + p1; // k는 Point 자료형이 아니다! // operator(k, p1)인 전역함수 연산자 오버로딩을 쓰자.

 

  • 전역함수를 이용한 연산자 오버로딩

전역함수 오버로딩은 왼쪽 항이 같은 객체의 자료형이 아니면 사용한다. 물론 같은 자료형도 쓸 수 있다.

class Point
{
    ...
    
    // friend 함수를 통해 private 값도 접근할 수 있음.
    freind const Point operator-(const Point& p1, const Point& p2);
    
    // friend 함수를 쓰지 않으면 Getter가 필요하다.
    int GetX() const { return x; }
    int GetY() const { return y; }
};

// freind 함수 O
const Point operator-(const Point& p1, const Point& p2)
{
    return Point(p1.x - p2.x, p1.y - p2.y);
}

// freind 함수 X
const Point operator-(const Point& p1, const Point& p2)
{
    return Point(p1.GetX() - p2.GetX(), p1.GetY() - p2.GetY());
}

int main()
{
    Point p1(2,3);
    Point p2(2,4);
    Point p3;
    
    p3 = p2-p1; // operator-(p2,p1)
    // (0, 1)
}

※ friend : 함수(freind 리턴 타입 함수 명칭)나 클래스(freind class 클래스 명칭)나 둘다 접근 제한을 무시한다.

 

1-6. STL에 필요한 주요 연산자 오버로딩

  • 함수 호출 연산자 오버로딩 : () 연산자

객체를 함수처럼 작동하도록 만드는 연산자다.

Print(10);
  1. 함수 호출 : Print가 함수 이름이다.
  2. 함수 포인터 : Print가 함수 포인터다.
  3. 함수 객체 : Print가 함수 객체다

 

struct Func
{
public:
    void operator()(int num) const
    {
        cout << "값 : " << num << endl;
    }
};

void Print1(int num)
{
	cout << "값 : " << num << endl;
}

int main()
{
    void (*Print2)(int) = Print1; // 함수 포인터
    Func Print3;
    
    Print1(10); // 함수를 이용
    Print2(10); // 함수 포인터 이용
    Print3(10); // 함수 객체 이용 // Print3.opeartor(10) 
}

※ struct와 class의 차이 : 기본 접근이 private, public의 차이다.

 

함수 객체를 이용은 다양한 방법으로 가능하다

// 객체 생성
Func func;
func(10); // 암시적
func.operator()(10); 명시적

// 임시객체
Func()(10); // 암시적
Func.operator()(10) // 명시적

※ 임시 객체 : 라인을 벗어나면 소멸된다.

 

  • 배열 인덱스 연산자 오버로딩 : [] 연산자

배열에 사용되는 [] 연사자를 객체에서도 사용하게 오버로딩 하였다. 

class Point
{
    ...
    
    int operator[](int idx) const
    {
        if(idx == 0)
            return x;
            
        else if(idx == 1)
            return x;
            
        throw "예외!";
    }
};

int main()
{
    Point pt(2,3); // pt[0]: 2, pt[1]: 3
    
    cout << pt[0] << ',' << pt[1] << endl; // pt.operator[](0), pt.operator[](1)
}

 

마찬가지로 컨테이너 객체에서도 사용한다.

class Array
{
    int *arr;
    int size;
    int capacity;
    
public:
    Array(int cap) : arr(0), size(0), capacity(cap)
    {
        arr = new int[capacity];
    }
    
    ~Array()
    {
        delete[] arr;
    }
    
    ...
    
    int operator[](int idx) const // arr[i] // Get
    {
        return arr[idx];
    }
    
    int& operator[](int idx) // arr[i] = 1; // Set
    {
        return arr[idx];
    }
};

 

  • 메모리 접근, 클래스 멤버 접근 연산자 오버로딩 : *, -> 연산자

스마트 포인터나 반복자 등의 특수한 객체에서 사용된다., 

class Point
{
    ...
};

class PointPtr
{
    Point* ptr;

public:
    PointPtr(Point *p) : ptr(p) {}
    ~PointPtr() // 소멸자 실행시 자동으로 ptr 삭제함.
    {
        delete ptr;
    }
};

int main()
{
    // 일반적인 할당
    Point *p1 = new Point(2, 3); 
    
    // 일반적인 사용
    p1->Print(); // p1.->Print()
    (*p1).Print(); // (*p1).Print()
    
    // 일반적인 해제
    delete p1;
    
    // 스마트 포인터 할당
    PointPtr p2 = new Point(5,5);
    
    // 스마트 포인터 사용
    p2->Print(); // p2.operator->()->Print()
    (*p2).Print(); // p2.operatpr*().Print()
    
    // 스마트 포인터 해제
    return 0; // return때 ~PointPtr 실행 -> 자동해제
}

 

1-7. 타입변환 연산자 오버로딩

  • 생성자를 이용한 타입변환
  • 타입 변환 연사자 오버로딩을 통한 타입 변환

 

  • 생성자 이용

특정 타입을 인자로 받는 생성자를 호출해 타입 변환(객체 생성 후 대입)을 한다.

class A
{
};

class B
{
public:
    B()		{ "B() 생성자"; }
    B(A& a) 	{ "B(A& a)  생성자"; }
    B(int n)	{ "B(int n) 생성자"; }
    B(double n) { "B(double n) 생성자"; }
};

int main()
{
    A a;
    int n = 10;
    double d = 5.5;
    
    B b;
    b = a;
    b = n;
    b = d;
    
    // 출력결과
    // B() 생성자
    // B(A& a) 생성자
    ...
}

※ explicit : 생성자의 형변환 금지

explicit Point(int a=0, int b=0) : x(a), y(b) {}

// pt = 10; // 불가능!
// pt = Point(10); // 가능!

 

  • 타입 변환 연산자 오버로딩 이용
class A
{
};

class B
{
public:
    operator A()
    {
        return A();
    }
    
    operator int()
    {
        return 10;
    }
    
    operator double()
    {
        return 5.5;
    }
};

int main()
{
    A a;
    int n = 10;
    double d = 5.5;
    
    B b;
    // 암시적
    a = b; // a = b.operator A()
    n = b;
    d = b;
    
    // 명시적
    a = b.opeartor A();
}

 

1-8 퀴즈

1) 다음 이항 연산자 '+'가 호출하는 오버로딩 함수는?

Point p1, p2;
p1 + p2;
더보기
p1.operator+(p2);
operator+(p1, p2);

 

2) 다음 세 인자를 받는 () 연산자 오버로딩 함수 선언은?

fun(10, 20, 30);
더보기
?? operator()(int, int, int);

 

3) 다음 배열 클래스 정수 원소를 참조하기 위한 []연산자 오버로딩 함수는?

arr[0];
더보기
arr.operator[](int);

 

4) 다음을 컴파일 될 수 있게 string 클래스를 작성하라

String s("Hello");
const char* sz = s;
더보기
class String
{
    char str[100];
    
public:
    String() {}
    String(const char* st) { strcpy(str, st); }
    
    operator const char*() const
    {
        return str;
    }
};

 

5) string 클래스 작성

const char* s = "Hello";
String str("Hi~~~");
s = str;
더보기
#include <iostream>
#include <cstring>

using namespace std;

class String
{
	char* str;

public:
	String()
	{
		
	}

	String(const char* st)
	{
		str = new char[strlen(st) + 1];

		strcpy(str, st);
	}

	const String& operator=(const char* st)
	{
		if (str != NULL)
			delete str;

		str = new char[strlen(st) + 1];
		strcpy(str, st);

		return *this;
	}

	friend ostream& operator<<(ostream& os, const String& str);
};

ostream& operator<<(ostream& os, const String& st)
{
	os << st.str;

	return os;
}


int main()
{
	const char* s = "Hello";
	String str("Hi~~~");

	cout << s << endl;
	cout << str << endl;
	
	str = s;

	cout << str << endl;

	return 0;
}

'C++ STL > Part 01 C++ 문법' 카테고리의 다른 글

4장 템플릿  (0) 2021.06.22
3장 함수 객체  (0) 2021.06.22
2장 함수 포인터  (0) 2021.06.17

댓글