21 분 소요

0. 기본 셋팅

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

class Base
{
    public:
        int value = 0xAA;
        Other* other = nullptr;
};

int main()
{
    Derived d1; // 원본

    Derived d2 = d1; // 복사 생성자
    Derived d3(d1); // 복사 생성자

    Derived d4; // 기본 생성자
    d4 = d1; // 복사 대입 연산자

    return 0;
}


1. 얕은 복사 (Shallow Copy)

  • 멤버 데이터를 비트열 단위로 똑같이 복사 (메모리 영역 값을 그대로 복사)
class Derived : public Base
{
    public:
        Derived() { other = new Other(); }
        ~Derived() { delete other; }
};
  • &d1
    image
  • &d2
    image
  • &d3
    image
  • &d4
    image

    같은 주소값공유한다. image


  • ⚠ 문제점

    모두 같은 주소를 가리키고 있기 때문에, 값이 변경되는 경우, d1, d2, d3, d4의 값이 모두 변경된다.


2. 깊은 복사 (Deep Copy)

  • 멤버 데이터가 참조(주소) 값이라면 데이터를 새로 생성 (원본 객체가 참조하는 대상까지 만들어서 복사)
class Other
{
    public:
        
        Other(const Other& o) { cout << "Other(const Other&)" << endl; }
        
};

class Derived : public Base
{
    public:
        
        Derived(const Derived& d)
        {
            value = d.value;
            other = new Other(*(d.other)); // 새로운 객체 생성         
        }

        Derived& operator=(const Derived& d)
        {
            value = d.value;
            other = new Other(*(d.other)); // 새로운 객체 생성
            return *this;
        }
        
};
  • &d1
    image
  • &d2
    image
  • &d3
    image
  • &d4
    image

    다른 주소값을 가진다. image


3. 호출 순서

class Member
{
    public:
        Member() { cout << "Member()" << endl; }
        Member(const Member& m) { cout << "Member(const Member&)" << endl; }
        ~Member() { cout << "~Member()" << endl; }

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

class Base
{
    public:
        Base() { cout << "Base()" << endl; }
        Base(const Base& b) 
        { 
            cout << "Base(const Base&)" << endl;  
            num = b.num; 
        }
        ~Base() { cout << "~Base()" << endl; }

        Base& operator= (const Base& b) 
        { 
            cout << "operator(const Base&)" << endl; 
            num = b.num; 
            return *this; 
        }
    public:
        int num = 0;
};


1. 복사 생성자

1. 암시적 복사 생성자 순서

1) 기본 클래스의 복사 생성자 호출
2) 멤버 클래스의 복사 생성자 호출
3) 멤버가 기본 타입일 경우 메모리 복사 (얕은 복사)

class Derived : public Base
{
    public:
        Derived() { cout << "Derived()" << endl; }
        ~Derived() { cout << "~Derived()" << endl; }
    public:
        Member m; 
};
  • 결과
    image


2. 명시적 복사 생성자 순서

1) 기본 클래스의 기본 생성자 호출
2) 멤버 클래스의 기본 생성자 호출

부모, 멤버 클래스 값이 복사되지 않는다.
모든 복사의 책임은 프로그래머가 가진다.

class Derived : public Base
{
    public:
        Derived() { cout << "Derived()" << endl; }
        ~Derived() { cout << "~Derived()" << endl; }

        Derived(const Derived& d) {cout << "Derived(const Derived&)" << endl; }
    public:
        Member m; 
};
  • 결과
    image
  • ⚠ 문제점

    부모, 멤버 클래스의 기본 생성자 호출
    부모, 멤버 클래스의 값이 복사되지 않는다

  • 부모, 멤버 클래스 생성자 지정
      class Derived : public Base
      {
          public:
              Derived() { cout << "Derived()" << endl; }
              ~Derived() { cout << "~Derived()" << endl; }
    
              Derived(const Derived& d) : Base(d), m(d.m) // 생성자 지정 필요
              {
                  cout << "Derived(const Derived&)" << endl; 
              }
          public:
              Member m; 
      };
    
  • 결과
    image


2. 복사 대입 연산자

1. 암시적 복사 대입 연산자 순서

1) 기본 클래스의 복사 대입 연산자 호출
2) 파생 클래스의 복사 대입 연산자 호출
3) 멤버가 기본 타입일 경우 메모리 복사 (얕은 복사)

class Derived : public Base
{
    public:
        Derived() { cout << "Derived()" << endl; }
        ~Derived() { cout << "~Derived()" << endl; }
    public:
        Member m; 
};
  • 결과
    image


2. 명시적 복사 대입 연산자 순서

- 알아서 해주는 것 없음

class Derived : public Base
{
    public:
        Derived() { cout << "Derived()" << endl; }
        ~Derived() { cout << "~Derived()" << endl; }

        Derived& operator= (const Derived& d)
        {
            cout << "Derived(const Derived&)" << endl;
            return *this;
        }
    public:
        Member m; 
};
  • 결과
    image


📑. 참고

카테고리:

업데이트:

댓글남기기