C++/C++ : Study

OOP 파트2 - (2) 복사 생성자

더블유제이플로어 2024. 11. 3. 01:56

Copy Constructor

중요한 Part이다.

◆  자동 생성되는 복사 생성자

  ● 사용자가 복사 생성자를 구현하지 않으면, 기본 복사 생성자가 사용된다.
  ● 멤버 변수들의 값을 복사하여 대입하는 방식이다!
  ● 포인터 타입의 멤버 변수가 존재할 때는 주의하자!

        ☞ 기본 복사 생성자는 포인터 타입의 변수 또한 복사하여 대입된다.
         즉, 포인터가 가리키는 데이터의 복사가 아닌 포인터 주소값의 복사이다!
  얕은 복사 (shallow copy) vs 깊은 복사(deep copy)

멤버 변수들을 값을 복사하여 대입하는 방식이다.
주의해야 할 부분은 기본 복사 생성자를 사용할 때 문제가 생길 수 있다.
포인터도 변수이다. 포인터를 복사를하면 주솟값이 복사가 되기 때문이다.
우리가 해야할 것은 깊은 복사이다.


Declaring Copy Constructor

◆  복사 생성자의 선언

  ● 동일한 타입의 const 참조자가 인라인 생성자

첫 번째로 알아볼 것은 복사 생성자를 알아본다.
복사 생성자는 컴파일러가 자동으로 만들어 주지만 사용자가 직접 만들 수도 있다.
생성자에 인자는 const로 자기와 같은 타입으로 참조자를 만들면 된다.

#include <iostream>
using namespace std;

class Player
{
public:
	Player(int hp, int xp)
		: hp{ hp }, xp{ xp }
	{
		cout << "생성자 호출됨" << endl;
	}

	// 복사 생성자
	Player(const Player& source)
	{
		cout << "복사 생성자가 호출됨" << endl;
	}

	void Print()
	{
		cout << hp << " " << xp << endl;
	}
private:
	int hp;
	int xp;
};

void PrintInformation(Player p)
{
	p.Print();
}

int main()
{
	Player p{ 10,2 };

	PrintInformation(p);

}

main 함수에서 Player p {10,2}; 이후에 디버깅을 위해서 중단점을 지정해 두었다.

main에 있는 p를 복사해서
PrintInformation에 인자로 사용해야 하기 때문에
복사 생성자가 자동으로 호출되었다.

복사 생성자로 인해서 일반 함수 인자에
hp, xp의 값이 들어갔는지 확인할 수 있다.


Implemening Copy Constructor

◆  얕은 복사 생성자의 구현

  ● 자동 생성된 복사 생성자의 행동
  ● 생성자 초기화 리스트를 사용한 방법

  ● 대입을 사용한 방법

  * 실제 자동 생성된 복사 생성자의 모습

컴파일러가 만들어주는 복사 생성자의 모습을 확인하기 위해
복사 생성자를 주석처리 한다.

자동으로 복사 생성자가 호출되었고, cout << 기능은 없어진 걸 확인할 수 있다.
복사를 하지 않았다면 PrintInformation()에서 10,2 가 출력되지 않았을 것이다.

컴파일러가 만들어주는 복사 생성자는 얕은 복사를 한다.=

원론적으로는 복사 생성자가 만들어줘서
0,0이 나오는게 맞다.
인자에서 아무것도 안하기 때문에 Null로 되어있다.
제대로 복사가 되기 위해서는
Player(const Player& other)
:hp{ other.hp }, xp{ other.xp }
{
cout << "복사 생성자가 호출됨" << endl;
}
복사를 해줘야 인자 값에 복사가 제대로 들어간다.
실수로 안해도 되어있는건 일부 컴파일러에서 최적화을 해주었다.
심지어 복사 생성자를 만들어주지 않아도 컴파일러가 자동으로 만들어준다.

복사 생성자에서 인자 부분에 멤버 변수 값을 대입하는 방식이 아니라
실제로는 메모리 블럭을 통째로 복사하는 경우로 알고있자

https://youtu.be/AF7tAZEzL7U?si=tIdENagCwPpq2SCo