오븐 노트

[C++] 얕은 복사 VS 깊은 복사 #1~2 본문

Develop/C++

[C++] 얕은 복사 VS 깊은 복사 #1~2

오 븐 2023. 2. 28. 20:13
#include <iostream>
using namespace std;

class Pet
{
public:
    Pet()
    {
        cout << "Pet()" << endl;
    }
    ~Pet()
    {
        cout << "~Pet()" << endl;
    }
    Pet(const Pet& pet)
    {
        cout << "Pet(const Pet&)" << endl;
    }

    Pet& operator=(const Pet& pet)
    {
        cout << "operator=(const Pet&)" << endl;
        return *this;
    }
};

class Player
{
public:
    Player()
    {
        cout << "Player()" << endl;
    }

    // 복사 생성자
    Player(const Player& player)
    {
        cout << "Player(const Player&)" << endl;
        _level = player._level;
    }

    // 복사 대입 연산자
    Player& operator=(const Player& player)
    {
        cout << "operator=(const Player&)" << endl;
        _level = player._level;
        return *this;
    }

public:
    int _level = 0;
};

class Knight : public Player
{
public:
    Knight()
    {
        //_pet = new Pet(); // 생성자 내에서 new 사용은 좋지 않은 습관이지만 간단히 예를 들기 위해 사용됨
    }

    Knight(const Knight& knight) : Player(knight), _pet(knight._pet) // 명시적으로 표기해야만 본인의 복사 생성자 버전으로 생성 가능
    {
        cout << "Knight(const Knight&)" << endl;

        _hp = knight._hp;
        //_pet = new Pet(*knight._pet); // 깊은 복사 // -> *(knight._pet) 접근하라는 의미의 포인터
    }

    Knight& operator=(const Knight& knight)
    {
        cout << "operator=(const Knight&)" << endl;
        
        Player::operator=(knight);
        _pet = knight._pet;

        _hp = knight._hp;
        //_pet = new Pet(*knight._pet); // 깊은 복사
        return *this;
    }

    ~Knight()
    {
        //delete _pet;
    }

public:
    int _hp = 100;
    //Pet* _pet;
    Pet _pet;
};

int main()
{
    Knight knight; // 기본 생성자
    knight._hp = 200;
    knight._level = 99;

    //cout << "--------------- 복사 생성자 ---------------" << endl;
    //Knight knight2 = knight; // 복사 생성자
    //Knight knight3(knight);

    Knight knight3; // 기본 생성자
    
    cout << "--------------- 복사 대입 연산자 ---------------" << endl;
    knight3 = knight; // 복사 대입 연산자

    // [복사 생성자] + [복사 대입 연산자]
    // 둘 다 만들지 않으면 컴파일러가 암시적으로 만들어줌

    // [얕은 복사 Shallow Copy]
    // 멤버 데이터를 비트열 단위로 '똑같이' 복사 (메모리 영역 값을 그대로 복사)
    // 포인터는 주소값 바구니 -> 주소값을 똑같이 복사 -> 동일한 객체를 가리키는 상태가 됨.
    // Stack : Knight1 [hp 0x1000] -> Heap 0x1000 Pet[    ]
    // Stack : Knight2 [hp 0x1000]
    // Stack : Knight3 [hp 0x1000]

    // [깊은 복사 Deep Copy]
    // 멤버 데이터가 참조(주소) 값이라면, 데이터를 새로 만들어준다 (원본 객체가 참조하는 대상까지 새로 만들어서 복사)
    // 포인터는 주소값 바구니 -> 새로운 객체를 생성 -> 상이한 객체를 가리키는 상태가 됨
    // Stack : Knight1 [hp 0x1000] -> Heap 0x1000 Pet[    ]
    // Stack : Knight2 [hp 0x2000] -> Heap 0x2000 Pet[    ]
    // Stack : Knight3 [hp 0x3000] -> Heap 0x3000 Pet[    ]

    // 실험)
    // - 암시적 복사 생성자 Steps
    // 1) 부모 클래스의 복사 생성자 호출
    // 2) 멤버 클래스의 복사 생성자 호출
    // 3) 멤버가 기본 타입일 경우 메모리 복사 (얕은 복사 Shallow Copy)
    // - 명시적 복사 생성자 Steps
    // 1) 부모 클래스의 기본 생성자 호출
    // 2) 멤버 클래스의 기본 생성자 호출
    
    // - 암시적 복사 대입 연산자 Steps
    // 1) 부모 클래스의 복사 대입 연산자 호출
    // 2) 멤버 클래스의 복사 대입 연산자 호출
    // 3) 멤버가 기본 타입일 경우 메모리 복사 (얕은 복사 Shallow Copy)
    // - 명시적 복사 대입 연산자 Steps
    // 1) 알아서 해주는거 없음

    // 객체를 복사 한다는 것은 두 객체의 값들을 일치시키려는 것
    // 따라서 기본적으로 얕은 복사 (Shallow Copy) 방식으로 동작함

    // 명시적 복사 -> [모든 책임]을 프로그래머에게 위임하겠다는 의미

    return 0;
}

[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 - 인프런 | 강의
 
C++ 카테고리의 글은 인프런 Rookiss님의 강의를 공부하며 정리하는 내용입니다.
이미 알고 있는 내용도 다시 정리 되어있을 수 있습니다.

 

모든 글은 제가 공부하기 위해 작성합니다.

'Develop > C++' 카테고리의 다른 글

[C++] TextRPG (OOP) #1~3  (0) 2023.03.03
[C++] 캐스팅 4총사  (0) 2023.03.03
[C++] 타입 변환 #4~5  (0) 2023.02.15
[C++] 타입 변환 #3  (0) 2023.02.15
[C++] 타입 변환 #1~2  (0) 2023.02.13