지난 시간에 Struct Class의 차이를 공부하면서 스텍에서 복사되고, 힙에 저장된 값만 가르킨다는 내용이 있었는데 그 부분이 얕은 복사, 깊은 복사이기에 더 디테일한 정리를 위해 공부한다.
얕은 복사를 이해하기 전에 이 간단한 문제를 풀어보면 좋을 거 같다. 아래와 같은 코드가 있을 때 출력되는 값은 무엇일까?
class TestClass
{
public class Person
{
public int _weight;
public int _height;
}
static void Main(string[] args)
{
Person jason = new Person
{
_height = 180,
_weight = 80
};
Person mack = jason;
mack._height = 170;
Console.WriteLine("{0}, {1}", jason._height, jason._weight);
Console.WriteLine("{0}, {1}", mack._height, mack._weight);
}
}
1번
구분 | 1번 |
---|---|
Jason | 180, 80 |
Mack | 170, 80 |
2번
구분 | 2번 |
---|---|
Jason | 170, 80 |
Mack | 170, 80 |
정단은 2번이다. 왜 일까?
클래스틑 레퍼런스 타입이며 힙 영역에 저장 된다. 하지만 여기서 jason
이라는 변수 자체가 힙 영역에 저장 된게 아니라 jason
은 힙 영역에 저장 된 값을 가르키고 있는 것 뿐이다.
그래서 mack = jason
을 하게 되면 jason이 가르키던 값을 mack도 가르키게 되고 서로 같은 값을 가르킨 후, mack의 값을 변경 해주니 힙에 저장 되어있던 원본의 값을 변경해주게 되므로 두 값 모두가 변경 된 것이다. 이게 얕은 복사의 개념이다.
그렇지만 Person
이라는 클래스를 통해 객체를 구분해서 비슷한 사람을 만들고 싶다. 위 예시 처럼 얕은 복사가 아닌 각 데이털 별도의 힙 공간에 새로운 객체를 담아두고 싶을 때는 깊은 복사가 필요하다.
아쉽게 C#에는 이를 지원하는 기능은 없고, 스스로 이를 구현 해야 한다. 위에서 만든 Class에 간단하게 깊은 복사를 하는 클래스를 만들어 준다.
public class Person
{
public int _weight;
public int _height;
public Person DeepCopy()
{
Person aPerson = new Person();
aPerson._weight = this._weight;
aPerson._height = this._height;
return aPerson;
}
}
해당 함수를 호출 하게 되면 new
를 통해 힙 영역에 새로운 객체를 할당하고, 새롭게 마련된 공간에 기존에 가지고 있던 값들을 넣으면서 복사를 하게 된다.
static void Main(string[] args)
{
Person jason = new Person
{
_height = 180,
_weight = 80
};
Person mack = jason.DeepCopy();
mack._height = 170;
Console.WriteLine("{0}, {1}", jason._height, jason._weight);
Console.WriteLine("{0}, {1}", mack._height, mack._weight);
}
만들어진 기능을 통해서 jason의 값을 깊은 복사 해주고, 키를 변경하면 이제는 얕은 복사 처럼 모두 변경 되는게 아닌 mack의 height 값만 변경된다.
C#에 있는 인터페이스 중 ICloneable 이라는 인터페이스가 위와 같은 깊은 복사를 위한 함수 틀을 만들어 두었기에 다른 이들과 함께 작업할 때는 해당 인터페이스를 상속 받아 사용하는 것도 좋은 방안이 될 것 같다.