본문 바로가기
카테고리 없음

C++ 복사 생성자란? 얕은복사와 깊은복사

by Hwan2 2019. 2. 24.
반응형

저희는 기본적으로 변수를 선언하고 데이터 값을 입력하는 과정을 다음과 같이 진행합니다.

 

int num_1 = 10;

int num_2 = num_1;

 

이런식으로 선언하는 것이 일반적입니다.

 

하지만 C++에서는 컴파일러가 다음과 같이 바꿔서 계산을 하게 됩니다.

 

int num_1(10);            //   int num_1 = 10;

int num_2(num_1);      //    int num_2 = num_1;

 

이렇게 보면 함수 안에 매개변수를 넣는 것 처럼 보입니다.

 

실제로도 비슷합니다.

 

즉, C++은 C와 다르게 int num_1 = 10; 의 과정을 int num_1(10)으로 해석한다는 말입니다.

 

그렇다면 왜? 굳이? 이런식으로 바꿔 진행하느냐.....

 

바로 Class 때문입니다.

 

Class를 선언한 후 사용하게 되면 Class엔 여러가지가 포함되게 됩니다.

 

그리고 Class안에 함수를 선언, 동적 메모리 할당 등..... 여러가지를 할 수 있게 되죠.

 

이러한 것들로 인해 대입연산 보단 함수 호출 형태로 받아 C++에서 정의한 복사 생성자를 통해

 

이를 사용자가 직접 전달 값을 변경해 줄 수 있도록 했습니다.

 

말로는 설명도 어렵고 이해도 안가니 코드로 설명하겠습니다.

 

(※만약 visual studio 2017 이상 버전을 사용하고 계신다면 이 글을(클릭) 읽어주세요. 그래야 컴파일 에러가 안납니다.)

 

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <cstring>

using namespace std;

class A {
    int num;
    char * name;
public:
     
    A(int num, char * name) {
        this->num = 10;
        setName(name);
    }

    void setName(char * name) {
        this->name = new char[strlen(name) + 1];
        strcpy(this->name, name);
    }

    void _printName() {
        printf("%X \n", name);
    }


};

int main(void) {

    A a_1(10, "Hwan");
    A a_2 = a_1;

    a_1._printName();
    a_2._printName();

    return 0;
}

 

 

 

a_1 과 a_2의 char *name이 가르키는 주소 값이 같은걸 알 수 있습니다.

 

33행을 보면 A a_2 = a_1을 해주고 있습니다. 즉 대입해주고 있습니다.

 

이말은 a_1 이 갖고 있는 값들은 a_2에게 전달하고 있는 겁니다.

 

즉!! 일반적인 생성자 호출이 된 것이 아니라, 값만 대입해 주고 있다는 소리입니다.

 

따라서 생성자는 호출이 안되게 되고 결국 아래 그림과 같은 모습을 하게 됩니다.

 

 

 

결국 a_1의 name의 값을 바꾸게 된다면 a_2의 name의 값도 바뀌게 됩니다. 어떻게 보면 참조자 형태가 되버린 것입니다.

 

이는 복사 생성자가 있기 때문인데, 사용자가 선언을 안해도 컴파일 시 자동으로 디폴트 복사 생성자가 실행이 됩니다.

 

디폴트 복사 생성자는 다음과 같은 형태를 갖고 있습니다.

 

A(const A &ref)  <<< 이 코드가 자동으로 생성되어 실행되게 됩니다.(사용자가 굳이 정의를 하지 않으면)

 

요 복사 생성자가 있기 때문에 int num(10); 이라는 문장도 성립이 가능하게 되는 것입니다.

 

그렇다면, 저희가 A a_2 = a_1;을 실행 시켰을 때 기대의 모습은 아래와 같습니다.

 

이러한 과정이 되기 위해서는 복사 생성자를 수정해 줄 필요가 있습니다.

 

#include <iostream>
#include <cstring>

using namespace std;

class A {
    int num;
    char * name;
public:
     
    A(int num, char * name) {
        this->num = 10;
        setName(name);
    }

    A(const A &ref) {       //디폴트 복사 생성자
        num = ref.num;
        name = ref.name;
    }


    void setName(char * name) {
        this->name = new char[strlen(name) + 1];
        strcpy(this->name, name);
    }

    void _printName() {
        printf("%X \n", name);
    }
};
 

 

 

 

짜잔!! 주소값이 달라진 것을 확인할 수 있었습니다.

 

이렇게 사용자가 직접 복사 생성자를 정의해 주는 것이 좋습니다.

 

물론, Class를 추가할 때 마다 new 키워드를 사용해 여러번 동적할당을 할 수도 있지만, 분명한 것은

클래스의 값을 복사해야할 상황도 온다는 것입니다. 때문에 이 개념을 잘 알아둬야 합니다.

 

다음은 왜? 복사생성자가 저렇게 생겼는지 설명하겠습니다.

(궁금하면 클릭!!)

반응형

댓글


스킨편집 -> html 편집에서