C# 파생클래스 객체의 메모리 표현에 관하여

[제목] C# 파생클래스 객체의 메모리 표현에 관하여

예전의 아티클 "C# 클래스 객체는 어떻게 Managed Heap에 표현되는가?"은 한 클래스 객체가 어떻게 Heap 메모리에 표현되는지에 대해 설명하였다. 이번 아티클에서는 Base 클래스를 갖는 파생클래스(Derived Class)가 어떻게 메모리에 표현되는지에 대해 알아보자.

우선 예제로서 2개의 C# 클래스를 가정해 본다. 클래스 A는 Base 클래스이고 B는 A를 상속해서 만든 파생클래스이다. A,B 클래스는 각각 2개의 필드를 가지고 있다. 그러면 이들 각각은 메모리 상에 어떻게 표현될까?

class A
{
	int a1;
	int a2;
}
class B : A
{
	int b1;
	int b2;
}
class Program
{
	static void Main(string[] args)
	{
		A a = new A(); 
		B b = new B();
		
		//디버거를 간편하게 정지하기 위해
		Console.ReadLine(); 
	}
}

먼저 A 객체가 힙에 표현된 모습을 보자. 아래 처럼 A 객체를 메모리에서 보면 a1, a2 라는 정수 필드 2개를 가지고 있다. (이는 사실 "C# 클래스 객체는 어떻게 Managed Heap에 표현..." 아티클에서와 동일한 결과이다)


클래스 객체 메모리 표현


그러면 파생클래스 B 객체는 어떻게 표현되는가? 아래에 보이는 바와 같이 파생클래스는 Base 클래스의 필드와 파생클래스의 필드들을 모두 갖게 된다. 여기서 Base 클래스의 필드가 public인지 private인지는 상관이 없으며 모두를 포함하게 된다.


파생클래스 객체 메모리 표현

여기서 한가지 주목할 점은 Base 클래스의 필드들이 먼저 공간을 차지하고 파생클래스 필드들은 그 뒤에 추가된다는 점이다. 만약 또 다른 클래스 C가 B로부터 다시 파생된다면, A, B, C 순서로 필드들이 공간을 차지하게 된다. (주: 메모리 상에서 하나의 클래스 내의 필드들의 순서는 개발자가 C# 코드에서 지정한 순서대로 되지 않을 수 있다. 이에 대해서는 "객체의 메모리 레이아웃에 대하여" 아티클 참조)

 

Name Hiding

만약 파생클래스가 Base 클래스의 필드와 동일한 필드명을 갖으면 어떻게 될까? 아래 예제에서 B 클래스는 a2라는 필드를 갖고 있는데, 이는 Base 클래스 A의 필드명과 동일하다.

class A
{
	public int a1;
	public int a2 = 1;
}

class B : A
{
	public int b1;        
	public new int a2 = 100; //new 없어도 동일        
}

이렇게 파생클래스가 Base 클래스와 동일한 필드를 갖게 되면, B 객체는 2개의 a2 필드를 갖게 된다.


Name Hiding 필드 레이아웃

그렇다면 동일한 필드명의 필드 a2를 어떻게 접근할 수 있을까? 이는 Object 레퍼런스의 타입 (변수 타입)에 따라 베이스 클래스 필드를 접근할 것인가, 파생클래스 필드를 접근할 것에 따라 달라진다. 즉, 아래 예제에서 처럼 B 파생클래스 객체 (변수 b)를 만든 후, 직접 b.a2 와 같이 필드를 접근하면 파생클래스 B의 필드를 사용하게 되고, 변수 b를 A로 Casting하여 변수 a에 할당한 경우 a.a2는 Base 클래스 A의 필드를 접근하게 된다. (또 다른 Factor로서 필드의 public, private 등의 엑세스 권한을 들 수 있다. 즉, 만약 B.a2가 private이면 외부에서 호출되는 a2필드는 베이스 public 멤버를 사용한다)

static void Main(string[] args)
{            
    B b = new B();

    // Base클래스 A의 필드 접근
    A a = (A)b;
    Console.WriteLine(a.a2); // 1

    // 파생클래스 B의 필드 접근
    Console.WriteLine(b.a2); // 100

    Console.ReadLine();
}

Name Hiding은 베이스클래스의 멤버를 하위의 파생클래스가 가리는 것으로 일반적으로 객체지향 프로그래밍(OOP)의 상속과 다형성에 대치되기 때문에 특별한 경우에만 사용하게 된다. Name Hiding은 Base클래스의 필드,상수,이벤트,속성,메서드,인덱서 등을 파생클래스에서 가리는 것을 일컫는데, 이 중 메서드 Hiding이 다른 것보다 많이 사용된다.

지금까지 파생클래스 객체의 실제 내용 즉 객체 데이타의 메모리 구조에 대해 살펴보았다. 객체지향 프로그래밍에서 이러한 객체 데이타와 더불어 또 다른 중요한 한 축은 Behavior 즉 메서드이다. 다음 아티클에서는 C# 파생클래스에서의 Virtual Method Table, Method Overriding/Hiding 등에 대해 살펴 보도록 하겠다.

 

관련 아티클




본 웹사이트는 광고를 포함하고 있습니다. 광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.