> For the complete documentation index, see [llms.txt](https://ezcode.gitbook.io/bnb-cpp/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ezcode.gitbook.io/bnb-cpp/class/copy-constructor.md).

# 복사생성자(Copy Constructor)

## 복사생성자

복사생성자는 같은 클래스의 객체를 복사하여 객체를 만드는 생성자이다.

### C++ 스타일의 초기화 <a href="#c-ec-8a-a4-ed-83-80-ec-9d-bc-ec-9d-98-ec-b4-88-ea-b8-b0-ed-99-94" id="c-ec-8a-a4-ed-83-80-ec-9d-bc-ec-9d-98-ec-b4-88-ea-b8-b0-ed-99-94"></a>

우리는 지금까지 다음의 방식으로 변수를 초기화 했다.

```cpp
int num = 20;
int &ref = num;
```

&#x20;c++ 에서는 다음과 같은 방식으로 변수의 초기화가 가능하다.

```cpp
int num(20);
int &ref(num);
```

&#x20;두가지 초기화 방식은 결과적으로 동일하다.

### 기본 복사생성자 <a href="#ea-b8-b0-eb-b3-b8-eb-b3-b5-ec-82-ac-ec-83-9d-ec-84-b1-ec-9e-90" id="ea-b8-b0-eb-b3-b8-eb-b3-b5-ec-82-ac-ec-83-9d-ec-84-b1-ec-9e-90"></a>

복사생성자를 명시적으로 선언하지 않으면 컴파일러는 객체의 멤버를 그대로 복사하여 객체를 생성하는 복사생성자를 자동으로 만든다.

```cpp
#include <iostream>
using namespace std;

class Point {
  int x;
  int y;
public:
  Point(int x = 0, int y = 0) : x(x), y(y) { }

  Point& setX(int x) {
    this->x = x;
    return *this;
  }

  Point& setY(int y) {
    this->y = y;
    return *this;
  }

  void show() {
    cout << "[" << x << "," << y << "]" << endl;
  }
};

int main() {
  Point p1(10, 50);
  Point p2 = p1; // 복사
  p1.setX(15).setY(35);
  cout << "p1 : ";
  p1.show();
  cout << "p2 : ";
  p2.show();
  return 0;
}
```

&#x20;위의 코드에서 `Point p2 = p1` 을 다음의 코드로 바꿔도 같은 결과가 된다.

```cpp
Point p2(p1);
```

&#x20;기본 복사생성자는 다음과 같은 형태이다.

```cpp
class ClassName {
  (...)

public :
  ClassName(const ClassName& copy) 
    : ( /* 초기화 리스트에서 모든 맴버 복사 */ ) 
  { }

  (...)
}
```

&#x20;위의 코드에 복사생성자를 만들어 보면 다음과 같이 된다.

```cpp
Point(const Point& copy)  // 복사생성자
  : x(copy.x), y(copy.y) 
{
  cout << "복사생성자 호출" << endl;
}
```

## 깊은 복사와 얕은 복사 <a href="#ea-b9-8a-ec-9d-80-eb-b3-b5-ec-82-ac-ec-99-80-ec-96-95-ec-9d-80-eb-b3-b5-ec-82-ac" id="ea-b9-8a-ec-9d-80-eb-b3-b5-ec-82-ac-ec-99-80-ec-96-95-ec-9d-80-eb-b3-b5-ec-82-ac"></a>

기본 복사생성자 처럼 모든 멤버를 각각 복사하는 방식을 얕은 복사라고 한다.\
다음 코드에서 얕은 복사의 문제점이 무엇인지 확인해 보자.

기존에 만들었었던 Person 클래스를 활용합니다.

{% code title="Person.h" %}

```cpp
#ifndef __PERSON__
#define __PERSON__

class Person
{
  char* name;
  int age;
public:
  Person(const char*, int);
  Person();
  ~Person();
  void showInfo() const;
  void setInfo(char*, int);
};

#endif
```

{% endcode %}

{% code title="Person.cpp" %}

```cpp
#include <iostream>
#include "Person.h"
#include <cstring>
using namespace std;

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

Person::Person() 
  : age(0)
{
  cout << "빈 객체 생성" << endl;
  name = NULL;
}

Person::~Person()
{
  cout << name << " 객체 소멸" << endl;
  delete[] name;
}

void Person::showInfo() const {
  cout << "이름 : " << name << endl;
  cout << "나이 : " << age << endl;
}

void Person::setInfo(char* myname, int myage) {
  name = myname;
  age = myage;
}

```

{% endcode %}

{% code title="main.cpp" %}

```cpp
#include <iostream>

#include "Person.h"
using namespace std;

int main() {
  Person man1("ki yong", 43);
  Person man2 = man1;
  man1.showInfo();
  man2.showInfo();
  return 0;
}
```

{% endcode %}

객체 소멸시 동적할당된 객체를 삭제할때 문제가 발생됩니다.

### 깊은복사 생성자 정의 <a href="#ea-b9-8a-ec-9d-80-eb-b3-b5-ec-82-ac-ec-83-9d-ec-84-b1-ec-9e-90-ec-a0-95-ec-9d-98" id="ea-b9-8a-ec-9d-80-eb-b3-b5-ec-82-ac-ec-83-9d-ec-84-b1-ec-9e-90-ec-a0-95-ec-9d-98"></a>

다음과 같이 복사생성자를 정의합니다.

**Person.h**에서 복사생성자를 선언합니다.

{% code title="Person.h" %}

```cpp
class Person {
(...)
public :
  Person(const Person& copy); // 복사생성자 선언

(...)
};

```

{% endcode %}

&#x20;**Person.cpp**에서 복사생성자를 정의합니다.

{% code title="Person.cpp" %}

```cpp
(...)

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

(...)

```

{% endcode %}
