값 타입과 참조 타입은 얕은 복사와 깊은 복사 방식이 다르다.

얕은 복사를 할 때, 값 타입은 복사되어진다.

하지만 참조 타입 멤버들은 동일한 참조값만 복사되어진다. 그래서 복사된 참조 타입은 메모리상에서 같은 오브젝트를 가리키게 된다.

반면에 깊은 복사를 할 때, 참조 타입은 각각 새로운 참조가 만들어지고 속해야 되는 새로운 오브젝트에로 전달된다.

그래서 참조 타입은 깊은 복사를 하면, 다른 오브젝트를 가리킬 수 있게 된다.

image-20220709143358538

[얕은 복사 - 예시 코드]

위에서 다루었던 내용대로, 얕은 복사를 할 때, 값 타입(Height)은 복사되어 새로 생성된 객체에 속하게 된다.

하지만, 참조 타입(Pet)은 동일한 참조값이 복사되고 복사되어진 참조값은 생성된 객체 Man과 ManShallowCopy에 참조되어, 결국 동일한 객체 Pet을 가리키게 된다.

using System;

namespace ShallowCopVSDeepCopy
{
	class Person
	{
		public string Name;
		public double Height;
		public Pet Pet;

		public Person(string name, double height, Pet pet)
		{
			Name = name;
			Height = height;
			Pet = pet;
		}

		// 얕은 복사 MemberwiseClone(): 값 타입은 복사, 참조 타입은 참조값만 복사 
		public Person ShallowCopy()
		{
			return (Person)MemberwiseClone();
		}
	}

	class Pet
	{
		public string Name;
		public double Height;

		public Pet(string name, double height)
		{
			Name = name;
			Height = height;
		}
	}

	internal class Program
	{
		static void Main(string[] args)
		{
			var Man = new Person("이동규", 174.5, new Pet("해피", 4.5));
			var ManShallowCopy = Man.ShallowCopy();
			Man.Pet.Height = 10;
			ManShallowCopy.Height = 190.5;
			// 값 타입과 참조 타입의 얕은 복사 비교 출력
			Console.WriteLine($"Man's Pet's Height: { Man.Pet.Height} " +
				$"/ ManShallowCopy's Pet's Height: {ManShallowCopy.Pet.Height}");
			Console.WriteLine($"Man's Height: {Man.Height} " +
				$"/ ManShallowCopy's Height: {ManShallowCopy.Height}");
		}
	}
}
Man's Pet's Height: 10 / ManShallowCopy's Pet's Height: 10
Man's Height: 174.5 / ManShallowCopy's Height: 190.5

[깊은 복사 - 예시 코드]

깊은 복사를 할 때, 참조 타입(Pet)은 동일한 참조값이 복사되어지는 것이 아니라, 각각 새로운 참조가 만들어지고 속해야 하는 새로운 객체(Woman, WomanDeepCopy)에 전달된다.

깊은 복사는 참조 타입이 다른 오브젝트를 가리킬 수 있게 해주지만, 직접 깊은 복사를 정의해주어야 한다.

예시 코드는 아래와 같다.

using System;

namespace ShallowCopVSDeepCopy
{
	class Person
	{
		public string Name;
		public double Height;
		public Pet Pet;

		public Person(string name, double height, Pet pet)
		{
			Name = name;
			Height = height;
			Pet = pet;
		}

		// 얕은 복사 MemberwiseClone(): 값 타입은 복사, 참조 타입은 참조값만 복사 
		//public Person ShallowCopy()
		//{
		//	return (Person)MemberwiseClone();
		//}

		// 깊은 복사는 직접 정의해야 함.
		public Person DeepCopy()
		{
			return new Person(Name, Height, new Pet(Pet.Name, Pet.Height));
		}
	}

	class Pet
	{
		public string Name;
		public double Height;

		public Pet(string name, double height)
		{
			Name = name;
			Height = height;
		}
	}

	internal class Program
	{
		static void Main(string[] args)
		{
			//var Man = new Person("이동규", 174.5, new Pet("해피", 4.5));
			//var ManShallowCopy = Man.ShallowCopy();
			//Man.Pet.Height = 10;
			//ManShallowCopy.Height = 190.5;
			//// 값 타입과 참조 타입의 얕은 복사 비교 출력
			//Console.WriteLine($"Man's Pet's Height: { Man.Pet.Height} " +
			//	$"/ ManShallowCopy's Pet's Height: {ManShallowCopy.Pet.Height}");
			//Console.WriteLine($"Man's Height: {Man.Height} " +
			//	$"/ ManShallowCopy's Height: {ManShallowCopy.Height}");


			//Console.WriteLine();

			var Woman = new Person("정은정", 165.5, new Pet("럭키", 5.5));
			var WomanDeepCopy = Woman.DeepCopy();
			Woman.Pet.Height = 6.5;
			WomanDeepCopy.Height = 145.8;
			// 값 타입과 참조 타입의 깊은 복사 비교 출력
			Console.WriteLine($"Woman's Pet's Height: {Woman.Pet.Height} " +
				$"/ WomanDeepCopy's Pet's Height: {WomanDeepCopy.Pet.Height}");
			Console.WriteLine($"Woman's Height: {Woman.Height} " +
				$"/ WomanDeepCopy's Height: {WomanDeepCopy.Height}");
		}
	}
}
Woman's Pet's Height: 6.5 / WomanDeepCopy's Pet's Height: 5.5
Woman's Height: 165.5 / WomanDeepCopy's Height: 145.8

정리

지난 블로그에서 == 연산자와 Equals() 메소드는 참조값만을 비교해준다는 것을 알 수 있었다. 그래서, 값 타입끼리 동일한지 비교하기 위해서는 Equals() 메소드를 오버라이드 해주어야 객체에 담긴 content를 비교할 수 있음을 알게 되었다.

이번에 연구한 내용도 비슷한 맥락인데, 얕은 복사는 참조 타입의 경우 참조값만을 복사하여 전달하기 때문에, 동일한 객체를 가리켜 얕게 복사한 객체의 멤버를 수정할 경우 전체 코드에 영향을 줄 수가 있다.

하지만 깊은 복사는 값 타입의 경우 새로 생성한 객체로 복사되어, 일부를 수정하더라도 전체 코드에 영향을 주지 않게 된다.

태그: ,

카테고리:

업데이트:

댓글남기기