1 minute read

5-1. 복사 생성자

✏️복사 생성자/ 디폴트 복사 생성자

  • C++에서 초기화 할 때,
    int num = n1;int num(n1) 이런 식으로 두가지가 가능했는데 이것이 객체에도 가능하다.

      class SoSimple{
          private:
              int num1;
              int num2;
          public:
              SoSimple(int n1, int n2) : num1(n1), num2(n2){}
              void Show(){
                  cout<<num1<<num2<<endl;
              }
      };
    

     이라고 하면 SoSimple sim1;이 있을때, SoSimple sim2 = sim1; 혹은 SoSimple sim2(sim1); 이렇게 객체를 복사할 수 있다.
    SoSimple sim2(sim1); 는 SoSimple의 객체를 생성해서 이름을 sim2라고 짓고 sim1을 인자로 받을 수 있는 생성자의 호출을 통해 생성을 완료한다는 것이다.

     이때, sim2를 인자로 받을 수 있는 생성자가 있어야하니깐

        SoSimple(SoSimple &copy) :num1(copy.num1), num2(copy.num2)  //복사생성자
        {}
    

    요런게 있어야 된다. 이게 바로 복사생성자 이다.

     사실 따로 정의되어 있지 않더라도 디폴트 복사 생성자가 자동으로 삽입되기 때문에 꼭 필요하나 순간 아니면 정의하지 않아도 괜찮다.

✏️explicit

  • 코드의 명확성을 위해 좋다.
  • 묵시적 변환을 막아준다.
    SoSimple sim2 = sim1; 라고 써도 SoSimple sim2(sim1);로 바뀌는데 이게 묵시적 변환이다.

  • 그래서
      explicit SoSimple(const SoSimple &copy) //참고로 &는 무조건 써줘야 컴파일 에러가 안난다!
          :num1(copy.num1), num2(copy.num2)
      {}
    

    라고 해놓으면 대입 연산자로 객체생성 및 초기화하는 것이 불가능하다.

5-2. 얕은복사와 깊은복사

✏️얕은복사

  • 디폴트 복사 생성자는 정말 단순하게 멤버 대 멤버를 복사한다. 따라서 멤버변수에 char *str과 같은 문자열이 있을 때,
    str에는 문자열의 주소가 들어있는데, 디폴트 복사 생성자가 만든 객체에 다른 주소를 갖는 문자열을 만드는게 아니라 같은 주소의 문자열을 그대로 가져가는 것이다. 따라서, 객체 하나가 소멸될 때, 포인터로 참조하는 문자열도 없어지는 것이라서 복사된 다른 객체는 소멸자가 실행이 안된다.

✏️깊은복사

  • 위의 문제를 해결하기 위한 것이다.
  • 직접 정의해야 한다.

    class Person{
      private:
        int age;
        char * name;
      public:
        Person(char *myname, int myage){
          int len = strlen(myname)+1;
          name = new char[len];
          strcpy(name, myname);
          age = myage;
      }
    
      ~Person(){  
        delete []name;
      }
    }
    

    라는 코드가 있을 때,

      Person(const Person &copy) : age(copy.age){
        name = new char[strlen(copy.name)+1];
        strcpy(name, copy.name);
      }
    

    이렇게 깊은 복사를 할 수 있도록 제대로 생성자를 정의 해줘야한다.

Tags: ,

Categories:

Updated: