-
윤성우 열혈 C++ 프로그래밍 11장) 연산자 오버로딩 2(대입연산자, 오버로딩, 함수 오버로딩, 스마트포인터, 펑터)PROGRAMMING/C++ 2024. 1. 8. 23:05
오늘 내용은 진짜 기억이 1도 안나서 아침에 읽다가 슬펐다.. 🥶 아좌좌 슬퍼하지말고!! 유튭에서 강의로 본 내용까지 깔끔하게 정리해보려고 한다.
(혹시 저작권에 문제가 있다면 수정하겠습니다!! 개인적인 공부용으로 정리함을 알려드립니당)
https://product.kyobobook.co.kr/detail/S000001589147
대입연산자
복사 생성자와의 공통점 : 정의하지 않으면 디폴트가 삽입되며 얕은 복사를 진행한다. 만약 동적할당을 하거나 깊은 복사가 필요하면 직접 정의해야한다.
복사 생성자와의 차이점 : 복사생성자는 새로 생성하는 객체에 기존의 객체를 사용했을 때 삽입되지만, 대입 연산자는 이미 생성 및 초기화된 객체의 대입에 사용된다.
Point pos(5, 7); Point pos2 = pos1; // 복사생성자 // 새로 생성하는 객체 pos2의 초기화에 기존에 생성한 객체 pos1이 사용 Point pos1(5, 7); Point pos2(3, 4); pos1 = pos2; // 대입연산자 // 이미 생성 및 초기화가 진행된 객체
//대입연산자 Point& operator=(const Point& ref){ // 참조형을 return함에 주의하라! delete []name; // 메모리 누수를 막기 위해 메모리 해제 int len = strlen(ref.name) + 1; name = new char[len]; strcpy(name, ref.name); this->xpos = ref.xpos; this->ypos = ref.ypos; return *this }
- 유도 클래스의 대입 연산자에는 아무런 명시를 하지 많으면, 기초 클래스의 대입 연산자가 호출되지 않는다.
(하지만, 디폴트 유도 클래스의 대입 연산자가 호출될 경우, 기초 클래스의 대입 연산자가 호출된다.)
배열의 인덱스 연산자 오버로딩
Simple[2] == Simple.operator[](2);
- 배열은 저장소의 일종으로 저장소에 저장된 데이터는 유일성이 보장되어야 하기 때문에, 대부분의 경우 저장소의 복사는 불필요하거나 잘못된 일이다. 그러므로 복사와 대입 연산을 private에 빈 상태로 둠으로써 복사와 대입을 원천적으로 막는 것이 좋은 선택이기도 하다!
✔️const 유무도 함수 오버로딩의 조건이 됨을 이용해 operator[] 함수도 함수 오버로딩할 수 있다!!!
객체의 저장을 위한 배열 클래스의 정의
1. 객체를 저장하는 배열 기반의 클래스
Point * arr; arr = new Point[len];
2. 객체의 주소값을 저장하는 배열 기반의 클래스 (사용 多)
장점) 깊은 복사냐 얕은 복사냐 하는 문제를 신경쓰지 않아도 되서 new, delete 연산이 복잡해보이지만 이 방법을 더 선호!
typedef Point * POINT_PTR; POINT_PTR * arr; arr = new POINT_PTR[len]; //--------------------- arr[0] = new Point(1, 2); arr[1] = new Point(2, 3); arr[2] = new Point(3, 4); delete arr[0]; delete arr[1]; delete arr[2]; delete []arr;
new 연산자 함수 오버로딩
new 연산자가 하는 일
1. 메모리 공간의 할당
2. 생성자의 호출 → 컴파일러가 해줌!
3. 할당하고자 하는 자료형에 맞게 반환된 주소 값의 형 변환 → 컴파일러가 해줌!
1번 메모리 공간의 할당만 오버로딩이 가능
void operator new(size_t size){ ... }
delete 연산자 함수 오버로딩
delete 연산자가 하는 일
1. 객체의 소멸자 호출
2. 주소값 전달
Q. new 연산자와 delete 연산자는 멤버함수의 형태로 오버로딩된다. 객체가 생성되기 전에 어떻게 이 두 연산자 호출이 가능할까?
A. new 연산자와 delete 연산자 모두 static 함수이기 때문이다!!!
포인터 연산자의 오버로딩
-> : 포인터가 가리키는 객체의 멤버에 접근
Number * operator->(){return this} num ->ShowData() == num.operator->() -> ShowData();
* : 포인터가 가리키는 객체에 접근
Number & operator*(){return *this}; (*num) == (num.operator*());
스마트포인터
: 포인터 역할을 하는 객체로 delete 연산이 자동으로 이루어지게 설계된다. 직접 정의해서 사용하는 경우는 드물며 라이브러리로 사용하면 충분하다!
()연산자의 오버로딩
: 오버로딩하면 객체를 함수처럼 사용할 수 있다! → 함수처럼 동작하는 클래스를 가리켜 펑터(Functor)라고 한다.
(개쩌는 예시는 책을 참고)
임시객체로의 자동 형 변환과 형 변환 연산자
: A형 객체가 와야 할 위치에 B형 데이터가 왔을 경우 B형 데이터를 인자로 전달받는 A형 클래스의 생성자 호출을 통해 A형 임시객체를 생성한다.
아래는 그 반대의 경우(int 자리에 Num 객체가 온 경우 Num 객체를 int로 인식)
//int형으로 형 변환해야 하는 상황에서 호출되는 함수 operator int(){ return num; }
스마트포인터에 대한 부가 설명은 아래 유튭(코드없는 프로그래밍님)을 참고했다. (강의 듣고 감동 받아서 바로 구독했다)
https://www.youtube.com/watch?v=tg34hwP0P0M&t=270s
https://www.youtube.com/watch?v=SQYPN8FVCAI
smart pointer의 종류
1. unique pointer - exclusive ownership으로 하나의 object를 다른 pointer가 가리키지 못한다.(move만 가능)
2. shared pointer - reference count를 이용해 object를 몇 개의 pointer가 가리키는지 확인한다. 다만 shared pointer의 경우 circular memory leak이 일어날 수 있다.
smart pointer는 RAII( Resource acquisition is initialization) 기법을 사용하고자 고안된 것으로 Resoure life cycle와 object life cycle가 같아지도록 한다. 여기서 Resoure는 heap 메모리가, object는 smart pointer으로 smart pointer를 사용함으로서 memery leak을 막을 수 있다!
#include <memory> // smart pointer를 사용하기 위해 포함해야 하는 라이브러리 std::unique_ptr<Simple> simpleptr = std::make_unique<Simple>(3);
참고로 smart ptr은 scope 에서만 유효하며, scope을 벗어나는 순간 deallocation한다.
만약 객체 배열을 동적 할당하고 싶다면 vector를 사용하면 된다.(자동으로 delete해준다.)
'PROGRAMMING > C++' 카테고리의 다른 글