[ C#.NET 기초강좌 #1] |
07. 참조 형식과 값 형식 |
작성자 : NGong | 작성일 : 2011-04-15 오후 4:21:36 |
E-mail : filmgdh골뱅이gmail.com | Homepage : http://blog.daum.net/coolprogramming |
.Net의 형식은 클래스(class), 구조체(struct), 인터페이스(interface), 델리게이트(delegate), 열거형(enum) 이렇게 다섯 가지입니다.
또 .Net은 아래 두 가지 기반의 형식으로 나뉩니다. (상속 구조 그림 = > http://msdn.microsoft.com/ko-kr/library/ms173104.aspx)
- 첫째, 참조 기반의 형식(class, interface, delegate)
- 둘째, 값 기반의 형식 (struct, enum)
첫째, 참조 기반 형식의 특징은
- 관리 힙에 할당됩니다.
- System.Value 형식이 아닌 모든 형식으로부터 파생될 수 있습니다.
- Sealed 형식이 아니라면 기본 형식으로 사용될 수 있습니다.
둘째, 값 기반 형식의 특징은
- 스택 메모리에 할당됩니다.
- 항상 System.Value 형식으로부터 파생됩니다.
- Sealed 형식입니다. 기본 형식으로 사용될 수 없습니다.
- 기본 생성자는 예약되어 있습니다.
1, 대표적인 참조 기반 형식(class)과 대표적인 값 기반 형식(struct)
C++에서 클래스(class)와 구조체(struct)는 완전히 동일한 것입니다.(디폴트 접근 한정자(클래스는 private, 구조체는 public) 만 빼면)하지만 .Net의 클래스와 구조체는 전혀 다르게 동작합니다.
클래스는 대표적인 참조 기반의 형식이며 구조체는 대표적인 값 기반의 형식입니다.
다음은 클래스와 구조체의 정의 및 사용 예제입니다.
-
using System;
class CPoint // Object에서 파생
{
private int x, y;
public CPoint(int _x, int _y)
{
x = _x;
y = _y;
}
public CPoint() // 클래스는 인자 없는 기본 생성자를 만들 수 있음.
{
x = 0;
y = 0;
}
public void Print()
{
Console.Write("base:{0}, ",GetType().BaseType);
Console.WriteLine("class:({0},{1})",x,y);
}
}
struct SPoint // ValueType에서 파생
{
private int x, y;
public SPoint(int _x, int _y)
{
x = _x;
y = _y;
}
//public SPoint(){} // 구조체는 기본 생성자를 만들 수 없음.(예약됨)
public void Print()
{
Console.Write("base:{0}, ", GetType().BaseType);
Console.WriteLine("struct:({0},{1})", x, y);
}
}
class Program
{
static void Main()
{
CPoint cpt = new CPoint(1, 1);
cpt.Print();
SPoint spt = new SPoint(5, 5);
spt.Print();
}
}
base:System.ValueType, struct:(5,5)
결과처럼 구조체(값 기반 형식)는 항상 ValueType으로부터 파생됩니다. 또 구조체(값 기반 형식)는 기본 생성자를 정의할 수 없습니다. 내부적으로 예약되어 있습니다.
GetType()는 자신의 형식 객체를 반환합니다. BaseType은 이 객체의 속성으로 부모 형식을 반환합니다. 다음에 설명하므로 지금은 클래스와 구조체에 집중!
다음은 위 예제의 메모리 그림입니다.
cpt는 힙 객체의 참조를 갖는 참조자(참조 변수)이며 spt는 객체 값 자체를 갖는 값 변수입니다. 또 cpt(참조자)는 Main() 함수 블록({})이 종료될 때 변수(참조자)는 바로 사라지지만 cpt가 가리키는 객체는 가비지 컬렉션 대상이 되는 힙 객체입니다. spt는 Main() 함수 블록({})이 종료될 때 변수와 객체(변수가 값 자체)가 모두 바로 사라지는 스택 객체입니다.
구조체는 기본 생성자 정의 없이도(내부적으로 예약됨) 호출할 수 있음!
-
using System;
class CPoint
{
private int x, y;
public CPoint(int _x, int _y)
{
x = _x;
y = _y;
}
public CPoint()
{
x = 0;
y = 0;
}
public void Print()
{
Console.Write("base:{0}, ", GetType().BaseType);
Console.WriteLine("class:({0},{1})", x, y);
}
}
struct SPoint
{
private int x, y;
public SPoint(int _x, int _y)
{
x = _x;
y = _y;
}
//public SPoint(){}
public void Print()
{
Console.Write("base:{0}, ", GetType().BaseType);
Console.WriteLine("struct:({0},{1})", x, y);
}
}
class Program
{
static void Main()
{
CPoint cpt = new CPoint();
cpt.Print();
SPoint spt = new SPoint();
spt.Print();
}
}
base:System.ValueType, struct:(0,0)
굿!
다음은 메모리 그림입니다.
구조체는 변수 선언이 곧 객체 생성입니다.
-
using System;
class CPoint
{
public int x, y;
public void Print()
{
Console.Write("base:{0}, ", GetType().BaseType);
Console.WriteLine("class:({0},{1})", x, y);
}
}
struct SPoint
{
public int x, y;
public void Print()
{
Console.Write("base:{0}, ", GetType().BaseType);
Console.WriteLine("struct:({0},{1})", x, y);
}
}
class Program
{
static void Main()
{
CPoint cpt; // 객체가 없으므로 말도 않됨!
cpt.x = 1; // 객체가 없는데 헐!
cpt.y = 1; // 객체가 없는데 헐!
cpt.Print();// 객체가 없는데 헐!
SPoint spt; // 변수 선언이 곧 객체 생성이므로 당근 가능!!
spt.x = 5; // 굿!
spt.y = 5; // 굿!
spt.Print();// 굿!
}
}
구조체는 변수 선언이 곧 객체 생성이며 모든 멤버 변수 초기화 후 사용할 수 있습니다.
다음은 메모리 그림입니다.
2, 참조 기반 형식(class)과 값 기반 형식(struct)의 복사
다음 클래스와 구조체 객체의 복사 동작을 설명합니다.클래스와 구조체의 복사 예제입니다.
-
using System;
class CPoint
{
public int x, y;
public CPoint(int _x, int _y)
{
x = _x;
y = _y;
}
public CPoint()
{
x = 0;
y = 0;
}
public void Print()
{
Console.WriteLine("class:({0},{1})", x, y);
}
}
struct SPoint
{
public int x, y;
public SPoint(int _x, int _y)
{
x = _x;
y = _y;
}
public void Print()
{
Console.WriteLine("struct:({0},{1})", x, y);
}
}
class Program
{
static void Main()
{
CPoint cpt1 = new CPoint(1, 1);
CPoint cpt2 = cpt1;
cpt1.Print();
cpt2.Print();
Console.WriteLine();
SPoint spt1 = new SPoint(5, 5);
SPoint spt2 = spt1;
spt1.Print();
spt2.Print();
}
}
class:(1,1)
struct:(5,5)
struct:(5,5)
클래스(참조 기반 형식)는 참조자가 복사되며 구조체(값 기반 형식)는 객체 자체가 복사됩니다.
다음은 예제의 메모리 그림입니다.
클래스는 두 참조자(cpt1,cpt2)가 하나의 객체를 참조하고 있으므로 객체의 값을 변경하면 두 참조자에 모두 반영되며 구조체는 두 변수(spt1,spt2)가 독립적인 객체를 가지므로 객체의 값을 변경하면 변경된 객체에만 반영됩니다.
클래스와 구조체 객체의 값 변경 예제입니다.
-
using System;
class CPoint
{
public int x, y;
public CPoint(int _x, int _y)
{
x = _x;
y = _y;
}
public CPoint()
{
x = 0;
y = 0;
}
public void Print()
{
Console.WriteLine("class:({0},{1})", x, y);
}
}
struct SPoint
{
public int x, y;
public SPoint(int _x, int _y)
{
x = _x;
y = _y;
}
public void Print()
{
Console.WriteLine("struct:({0},{1})", x, y);
}
}
class Program
{
static void Main()
{
CPoint cpt1 = new CPoint(1, 1);
CPoint cpt2 = cpt1;
cpt1.Print();
cpt2.Print();
cpt1.x = cpt1.y = 2;
cpt1.Print();
cpt2.Print();
Console.WriteLine();
SPoint spt1 = new SPoint(5, 5);
SPoint spt2 = spt1;
spt1.Print();
spt2.Print();
spt1.x = spt1.y = 6;
spt1.Print();
spt2.Print();
}
}
class:(1,1)
class:(2,2)
class:(2,2)
struct:(5,5)
struct:(5,5)
struct:(6,6)
struct:(5,5)
cpt1객체와 spt1객체를 변경한 출력입니다. cpt1은 cpt2와 같은 객체를 참조하므로 하나의 객체를 변경하면 두 참조자에 모두 값이 반영됩니다.
위 예제의 메모리 그림입니다.
해서 참조 기반 형식을 값 복사(깊은 복사) 하려면 인터페이스를 사용해야 합니다. 요건 담에...
3, int의 복사
int는 값 기반 형식입니다. 기본 형식에 대한 정리는 다음에...c#의 기본 형식 => http://msdn.microsoft.com/ko-kr/library/ya5y69ds.aspx
위 표에 나와 있는 형식 중 object와 string을 제외한 모든 형식은 값 기반 형식입니다.
위 내용처럼 모든 C#의 수치형 형식은 모두 구조체(값 기반 형식)입니다.
다음은 int 변수(객체)의 초기화입니다.
-
using System;
class Program
{
static void Main()
{
int n1 = 0;
int n2 = new int();
int n3 = new System.Int32();
Console.WriteLine("{0} {1} {2}", n1, n2, n3);
}
}
int 는 System.Int32 구조체의 별칭이며 기본 생성자에서 0으로 초기화됩니다. 기본 값 => http://msdn.microsoft.com/ko-kr/library/83fhsxwc.aspx
모든 수치형은 값 기반 형식이므로 아래처럼 복사됩니다.
-
using System;
class Program
{
static void Main()
{
int n1 = 10;
int n2 = n1; //1.
Console.WriteLine("{0} {1}", n1, n2);
n1 = 20; //2.
Console.WriteLine("{0} {1}", n1, n2);
n2 = 30; //3.
Console.WriteLine("{0} {1}", n1, n2);
}
}
20 10
20 30
다른 수치형도 이처럼 동작하겠죠?
아래는 간단한 메모리 그림입니다.
오늘은 여기까지~~~
'오래된 흔적 > C#.NET 기초강좌 #1' 카테고리의 다른 글
[HOONS C#.NET 기초강좌 #1] 06. 네임스페이스(namespace) (0) | 2012.03.05 |
---|---|
[HOONS C#.NET 기초강좌 #1] 05. C# 클래스 (0) | 2012.03.05 |
[HOONS C#.NET 기초강좌 #1] 04. 객체지향 (0) | 2012.03.05 |
[HOONS C#.NET 기초강좌 #1] 03. 함수(Function) (0) | 2012.03.05 |
[HOONS C#.NET 기초강좌 #1] 02. Main() 함수, 변수, 상수 (0) | 2012.03.05 |