어떠한 '클래스를 상속받은 객체'를 복사 생성자, 복사 대입 연산자를 통해 복사할때
'주의 해야할 점'이 한가지 있는데 바로 '컴파일러는 알잘딱 해주지 않는다'는 거임
이게 무슨 소리냐
1) 깊은 복사 [ 명시적 복사 생성자, 명시적 복사 대입 연산자 ]
class Knight : public Player
{
public:
Knight()
{
}
Knight(const Knight& knight)
{
cout << "Knight(const Knight&)" << endl;
_hp = knight._hp;
}
Knight& operator=(const Knight& knight)
{
cout << "operator=(const Knight&)" << endl;
_hp = knight._hp;
return *this;
}
~Knight()
{
}
public:
int _hp = 100;
Pet _pet;
};
위와 같은 'Player를 상속받고 Pet 객체를 가지고 있는 클래스'가 있을때
int main()
{
Knight knight; // 기본 생성자
knight._hp = 200;
cout << "-------------------복사생성자-------------------" << endl;
Knight knight2 = knight; // 복사 생성자
cout << "-------------------복사 대입 연산자-------------------" << endl;
Knight knight4; // 기본 생성자
knight4 = knight; // 복사 대입 연산자
return 0;
}
위의 코드처럼 '복사 생성자, 복사 대입 연산자를 호출'하면 '어디까지 복사를 해줄까'를 보면
놀랍게도 Player, Pet을 '기본 생성자로 생성'하는걸 볼 수 있음
즉 Player, Pet 안에 있는 데이터들을 안옮겨 준다는 얘기임
Player()
Pet()
-------------------복사생성자-------------------
Player()
Pet()
Knight(const Knight&)
-------------------복사 대입 연산자-------------------
Player()
Pet()
operator=(const Knight&)
~Pet()
~Pet()
~Pet()
위와 같은 결과가 출력됨
즉 '명시적으로' 복사 생성자와 복사 대입 연산자를 '호출 할때'에는
부모 클래스랑 멤버 클래스를 '컴파일러가' 알잘딱 해주지 않기 때문에 '프로그래머가' 알잘딱해줘야한다~
2) 앝은 복사 [ 암시적 복사 생성자, 암시적 복사 대입 연산자 ]
class Knight : public Player
{
public:
public:
int _hp = 100;
Pet _pet;
};
위 처럼 복사 생성자, 복사 대입 연산자에 대한 정의가 없을 때
int main()
{
Knight knight; // 기본 생성자
knight._hp = 200;
cout << "-------------------복사생성자-------------------" << endl;
Knight knight2 = knight; // 복사 생성자
cout << "-------------------복사 대입 연산자-------------------" << endl;
Knight knight4; // 기본 생성자
knight4 = knight; // 복사 대입 연산자
return 0;
}
위의 코드를 다시 실행 시켜보면
Player()
Pet()
-------------------복사생성자-------------------
Player(const Player&)
Pet(const Pet&)
-------------------복사 대입 연산자-------------------
Player()
Pet()
operator=(const Player&)
operator=(const Pet&)
~Pet()
~Pet()
~Pet()
깊은 복사와 다르게 결과가 출력되는걸 볼 수 있음
'부모 클래스와 맴버 클래스'를 기본 생성자로 생성 하는 것이 아닌 '복사 생성자, 복사 대입 연산자'로 생성하는데
와! 컴파일러 알잘딱! 이라고 착각 할 수가 있음
하지만 이러한 얕은 복사의 경우 '치명적인 문제'가 하나 있음
바로 포인터의 경우 '포인터의 주소값까지 복사'해버린다는 거..
객체를 복사 하고 '원본과 복사본'의 메모리를 delete로 반환할때
똑같은 주소값을 가지고 있는, 즉 같은 객체에 두번 delete하게 되는거
그럼 크래쉬가 나게됨..