본문 바로가기

C#

[C#] MemberwiseClone() 함수

◈ 정의

Object 클래스의 protected 멤버 함수이며 객체 복사를 위한 함수



◈ 설명

객체는 참조를 기본으로 하기 때문에 객체 변수를 사용한 할당은 참조값을 넘겨주는 의미이지 메모리 차원에서의 복사 개념은 아니다. 

따라서 아무리 할당을 해도 넘어가는 것은 참조값 뿐이다.


이러한 문제를 해결하기 위해서 MemberwiseClone() 함수를 제공한다. 이 함수는 메모리 차원에서 객체의 복사본을 생성하는 함수이다.


객체복사

-. 얕은 복사: object의 MemberWiseClone()이 자동으로 지원해준다.

-. 깊은 복사: 직접 구현해서 사용해야 한다.


☞ protected의 사용

: MemnberwiseClone()의 접근 지정자는 protected이다. 접근 지정자가 protected인 멤버는 일반적인 접근에서는 private의 성격을 지니고 있지만 직접 상속을 받는 파생 클래스의 입장에서는 완전한 public으로 사용할 수 있다.

즉 MemberwiseClone()은 protected 함수이기 때문에 상속받는 클래스 내에서만 사용할 수 있는 특징이 있다.


예)

class Top

{

public int a = 100;

public int b = 200;

}


class Child

{

public int age = 10;

public object height = 20;

public Top grand = new Top();

public Child Copy()

{

return ( Child )this.MemberwiseClone();

}

}


class MemberwiseCloneTest

{

public static void Main()

{

Child c1 = new Child();

Child c2 = c1.Copy();


Console.WriteLine(object.ReferenceEquals(c1, c2));

Console.WriteLine(object.ReferenceEquals(c1.height, c2.height));

Console.WriteLine(object.ReferenceEquals(c1.grand, c2.grand));

}

}


위의 예에서 Child를 복사하기 위해서 내부에 Copy() 함수를 구현하고 있다. Copy() 함수에서는 자신의 복사본을 리턴하는 MemberwiseClone()이 사용되었다. Object를 상속하고 있는 Chile 클래스 내부에서 protected 함수인 MemberwiseClone()을 사용하는 것은 정당한 protected의 사용법이다.


Chile 객체를 만든 후 새로운 복사본을 만들기 위해서 Copy() 함수를 호출하고 있다.


c1의 메모리가 복사되어 c2가 되었다. 새로운 메모리가 하나 만들어졌기 때문에 c1과 c2의 참조값은 다를 수밖에 없다.


그런데 여기서 하나 주의해야 하는 것이 있다. c1의 메모리라고 할 수 있는 것이 무엇인가 이다. c1의 메모리로 볼 수 있는 것은 age, height, grand정도이다. age는 값타입이기 때문에 그 자체를 메모리로 간주하면 된다. 문제가 되는 것은 height와 grand이다. height와 grand는 현재 참조값을 나타내는 참조 변수이며, 실제 메모리는 힙에 존재한다. 그렇다면 c1의 메모리는 정확하게 어디까지인가를 한번 더 생각해봐야 한다.


참조 변수를 4바이트로 가정하면 c1과 c2의 메모리는 각각 12 바이트 정도 된다. 그렇다면 age는 복사되었지만 height와 grand는 참조 변수끼리의 복사가 된다. 이렇게 되면 진짜 메모리 복사가 아니잖은가?


결과를 보면 c1과 c2는 참조비교에서 false로 그 값이 다른 것을 알 수 있다. 또 다른 복사본이 생성되었지만 c1 내의 참조형 멤버들은 참조값만을 복사하고 있따. c1과 c2의 heigth와 grand의 참조비교가 true인 것은 동일한 참조값을 가지고 있다는 증거이다.


이것은 참조타입으로 된 멤버 필드는 참조값만이 복사되고 메모리 차원의 복사는 이루어지지 않았기 때문이다.

'C#' 카테고리의 다른 글

[C#] Thread(스레드)  (0) 2018.07.16
[C#] Naming 규칙  (0) 2018.07.16
[C#] enum의 Flag 연산  (0) 2018.07.16
[C#] Delegate  (0) 2018.07.16
[C#] Boxing / UnBoxing / as  (0) 2018.07.11