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);
- 함수 호출 : Print가 함수 이름이다.
- 함수 포인터 : Print가 함수 포인터다.
- 함수 객체 : 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 |
댓글