헷갈리는게 너무 많아졌다. 이론을 머릿속에 집어넣는 것 보단 회독을 하는게 좋을 듯.
A1. virtual (자료형)(함수명)() 기본구조
Q. 그래서 왜 씀?
언리얼의 Interact(상호작용) 기능을 만든다고 치자. 그럼 문, 보물상자, NPC 등 상호작용 대상이 수천개다.

여기서 Target이 어떤 오브젝트인지 알 필요 없이 상속 받았으면 실행하라고 시킬 수 있음.
A2. vector<기본클래스*>_ 변수;
#include <vector>
vector<Phone*> Phones;
vector는 길이가 마음대로 늘어났다 줄어들었다 하는 편한 동적배열
그러므로 뒤에 해제 delete도 해줘야함.
size_t 인 이유가 뭔가요for(size_t i = 0; i < Phones.size(); i++){
Phones[i].Display();
}
vector::size() 함수 자체가 반환하는 타입이 size_t(size_type)으로 정해져 있기 때문
(size_t는 절대 음수가 될 수 없는 자료형 unsigned int와 크기가 같음)
#include <vector>
vector<Phone*> Phones;
Phones.push_back(new Samsung());
A3. push_back은 맨 뒤에 새로운 칸을 만들어서 데이터를 넣는 함수이다.
Phones.push_back(new Samsung());은 Phones[0]에 Samsung을 동적할당 해준거임.
이건 선언한 순서대로 Phones[1], Phones[2] 가 됨
A4. 소멸자는 클래스가 할당이 해제 될때 실행됨. 생성자의 반대라고 알면 될 듯
virtual ~Phone() {delete Phone;}
A.
1. 클래스 내부 동적할당 해제할때
2. 아까 main에서 동적할당 했을때 delete Phones[i] 반복문을 돌리는데 이렇게 되면 기본 클래스에 있는 메모리만 해제하게 됨. virtual ~Phone(){}는 delete가 파생 메모리들도 찾아갈 수 있게 인식키 같은게 되는거임.
Delete Phones[0]을 실행하면 다음과 같이 행동한다.
Phone[0] 주소로 간다.
포인터 타입이 Phone*인걸 확인
Phone의 메모리만 해제
결과 : Samsung 객체 중 Phone과 겹치는 기본 클래스만 지워지고 파생 클래스의 데이터는 메모리에 남아 메모리 누수 됨.
결론
Phones[0]은 Samsung을 가리키는가? -> YES
컴퓨터는 지울 때 Samsung인 걸 자동으로 아는가? -> NO. (virtual이 있어야함)
왜 virtual을 쓰는가? -> 기본 클래스에 상속된 파생 클래스의 할당된 메모리를 해제 하기 위해
A5.
std::unique_ptr<Phone> ptr; // 기본형
포인터의 주소 복사가 안되는 포인터 옮기는건 move 사용해서 가능. 즉 같은 주소를 가진 포인터가 두개 이상 존재 할 수 없음
std::unique_ptr<Phone> ptr = std::make_unique<Phone>;
std::unique_ptr<Phone> ptr2 = ptr; // 복사가 안됨
여기서 좀 헷갈렸는데 어려울것 없다. 그냥 원래 보던 함수랑 똑같다고 생각하면 됨.
unique_ptr<Phone> ptr = make_unique<Phone>;
unique_ptr<Phone> : 포인터 주소로 갔을때 값의 크기가 클래스 Phone만큼(포인터 변수 ptr 주소값의 크기 X) 입니다 안심하고 들어오세요~ 라는 뜻
ptr : 포인터 변수
make_unique<Phone> : 클래스 Phone 크기만큼 동적할당 하겠습니다.
즉, (자동반환이 되고 주소값을 가리키는 포인터는 하나인) Phone 크기만큼 동적할당을 할게요 !
-> ptr 포인터 변수에 동적할당 할게요 !
-> 포인터 변수 주소의 값에는 클래스 Phone만큼의 크기가 있으니 안심하고 들어오세요 !
처음에 너무 낯설어서 헷갈렸지만 거꾸로 읽으면 그냥 포인터 선언 한거임..
if(auto a_shared = ptr.lock()) <- 이놈 때문에 미칠 것 같아요. 이거 뭐죠A. weak_ptr은 레퍼런스 카운트를 증가시키지 않는 약한 참조방식으로 동작하는 스마트 포인터 입니다.
라고 하지만 글로만 보면 이해가 안된다. 그렇다고 또 예문을 보면 미쳐 돌아버릴 것 같다.
class B {
public:
std::weak_ptr<A> a_ptr;
void useA() {
if (auto a_shared = a_ptr.lock()) { // 유효한지 확인
a_shared->say_hello();
} else {
std::cout << "A is no longer available.\n";
}
}
};
일단은 모르는게 너무 많으니까 뭔지 보고 가자
auto a_shared에서 auto 자료형은 뭐죠**
A. auto는 컴파일러가 타입을 추론 한다.
즉, 초기값의 형식에 맟춰 선언하는 인스턴스(변수)의 형식이 '자동'으로 결정된다.
a_ptr.lock()에서 .lock() 또 뭐에요??
A. a_ptr.lock()은 weak_ptr이 보고 있는 객체가 진짜로 살아 있는지 확인하고 if 안 에서는 사용할 수 있게 잠금을 해놓겠다이다.
이 두개를 이해해야지만 weak에 대한 이해를 할 수 있음
지금 위에서 한 week_ptr은 약한참조(보기만 할 수 있음) 주소 값이 살아 있으니까 auto가 std::shared_ptr<A>로 승격 된다. << 이때 레퍼런스 횟수가 1 올라감, 죽었으면 nullptr 반환
즉, std::shared_ptr< A > a_shared가 됐다
A도 B에 포인터를 쓰고싶고, B도 A에 쓰고싶은데 둘이 shared_ptr을 쓰면 무한반복 되니까
B에서는 weak_ptr을 써서 if(auto a_ptr = ptr.lock()){} 스코프 안에서만 A를 참조해서 쓴다!!
vector, std::unique_ptr, push_back, weak_ptr 다 모르겠다!!
넣을때는 make_unique, 상자는 vector<unique_ptr<T>>, 모르면 외워!!