[C#] 17. 구조체(struct) 그리고 값 형식 참조(Value type reference)와 참조(포인터) 형식 참조(Reference type reference)
안녕하세요. 명월입니다.
이 글은 C#에서의 구조체(struct) 그리고 값 형식 참조(Value type reference)와 참조(포인터) 형식 참조(Reference type reference)에 대한 글입니다.
이전 글에서 제가 클래스와 인스턴스 생성에 대해서 설명한 적이 있습니다.
링크 - [C#] 09. 클래스 생성하는 방법(생성자, 소멸자)
링크 - [C#] 10. 인스턴스 생성(new)과 메모리 할당(Stack 메모리와 Heap 메모리) 그리고 null
기본적으로 C#에서 구조체라는 것은 형태가 구조는 클래스와 같습니다.
using System;
namespace Example
{
// 구조체 생성
struct Example
{
// 맴버 변수
private int data;
// 맴버 변수 설정 함수
public void SetData(int data)
{
// 맴버 변수에 값 설정
this.data = data;
}
// 출력 함수
public void Print()
{
// 콘솔 출력
Console.WriteLine("data - " + this.data);
}
}
class Program
{
// 실행 함수
public static void Main(string[] args)
{
// 인스턴스 생성
Example ex = new Example();
// 값 설정
ex.SetData(10);
// 함수 실행
ex.Print();
// 아무 키나 누르시면 종료합니다.
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
그럼 무엇이 다른가 했을 때, 결정적으로 구조체는 값 형식 참조를 하고 클래스는 참조 형식 참조를 하는 차이입니다.
즉, 클래스의 경우는 Heap에 클래스의 인스턴스가 생성이 되고 Stack에 변수로 주소값을 설정합니다.
그럴 경우 Stack에 다른 변수로 이꼴(=)를 사용해서 값을 설정하거나 파라미터로 클래스를 넘겨서 설정을 바꾸면 당연히 원 Stack 변수에도 영향이 갑니다.
using System;
namespace Example
{
// 클래스 생성
class Example
{
// 맴버 변수
private int data;
// 맴버 변수 설정 함수
public void SetData(int data)
{
// 맴버 변수에 값 설정
this.data = data;
}
// 출력 함수
public void Print()
{
// 콘솔 출력
Console.WriteLine("data - " + this.data);
}
}
class Program
{
// 실행 함수
public static void Main(string[] args)
{
// 인스턴스 생성
Example ex = new Example();
// 값 설정
ex.SetData(10);
// ex 인스턴스를 ex1에 대입
Example ex1 = ex;
// ex1의 함수로 맴버 변수 값 설정
ex1.SetData(20);
// ex를 출력하면 값이 변경되어 있다.
ex.Print();
// 아무 키나 누르시면 종료합니다.
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
값을 보면 ex 변수의 data값이 변경되어 있습니다. 즉, 아래와 같은 형태로 되어 있습니다.
이걸 예전에 설명했습니다.
구조체는 다릅니다.
using System;
namespace Example
{
// 구조체 생성
struct Example
{
// 맴버 변수
private int data;
// 맴버 변수 설정 함수
public void SetData(int data)
{
// 맴버 변수에 값 설정
this.data = data;
}
// 출력 함수
public void Print()
{
// 콘솔 출력
Console.WriteLine("data - " + this.data);
}
}
class Program
{
// 실행 함수
public static void Main(string[] args)
{
// 인스턴스 생성
Example ex = new Example();
// 값 설정
ex.SetData(10);
// ex 인스턴스를 ex1에 대입
Example ex1 = ex;
// ex1의 함수로 맴버 변수 값 설정
ex1.SetData(20);
// ex를 출력하면 값이 변경되어 있지 않다.
ex.Print();
// 아무 키나 누르시면 종료합니다.
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
위의 소스에서 Example 클래스(class)에서 구조체(struct)로 바꾼 것 밖에 없습니다만 결과는 다릅니다.
위처럼 생성이 되어있습니다. 이처럼 구조체는 이꼴(=)만으로 구조체가 복제가 되었습니다. 이것을 C#에서는 값 형식 찹조(Value type reference)라고 하고 위 클래스처럼 포인터만 복사가 되는 것을 참조 형식 참조(Reference type reference)라고 합니다.
또, 우리가 원시 데이터를 사용할 때, int a = 1; int b = a; 라고 했을 때 b의 값을 변경해도 a의 값이 변하지 않습니다. 이것도 값 형식 참조입니다.
그럼 이 구조체(struct)를 함수에서 넘길 때 값 형식 참조가 아닌 참조 형식 참조로 넘기고 싶을 때가 있습니다. 그럴 때는 ref 키워드를 사용해서 참조형식으로 바꿀 수 있습니다.
using System;
namespace Example
{
// 구조체 생성
struct Example
{
// 맴버 변수
private int data;
// 맴버 변수 설정 함수
public void SetData(int data)
{
// 맴버 변수에 값 설정
this.data = data;
}
// 출력 함수
public void Print()
{
// 콘솔 출력
Console.WriteLine("data - " + this.data);
}
}
class Program
{
// ref를 사용해서 파라미터에서 값 형식 참조가 아닌 참조형식 참조로 변경이 가능하다.
static void SetExampleData(ref Example p1)
{
p1.SetData(20);
}
// 실행 함수
public static void Main(string[] args)
{
// 인스턴스 생성
Example ex = new Example();
// 값 설정
ex.SetData(10);
SetExampleData(ref ex);
// ex를 출력하면 값이 변경되어 있다.
ex.Print();
// 아무 키나 누르시면 종료합니다.
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
당연한 이야기이지만 ref를 빼면, 구조체는 파라미터에서 값 형식 참조로 넘기기 때문에 ex의 값이 변경되어 있지 않다.
클래스의 경우는 참조 형식 참조이기 때문에 필요없는 키워드입니다.
구조체는 클래스와 다르게 몇가지 특성이 있습니다.
먼저 파라미터가 없는 생성자는 만들 수 없습니다.
맴버 변수를 public으로 외부에서 초기 값을 설정한다면 new 키워드를 사용할 필요가 없습니다.
using System;
namespace Example
{
// 구조체 생성
struct Example
{
// 맴버 변수
public int data;
// 출력 함수
public void Print()
{
// 콘솔 출력
Console.WriteLine("data - " + this.data);
}
}
class Program
{
// 실행 함수
public static void Main(string[] args)
{
// new 키워드가 없음
Example ex;
// 맴버 변수 설정
ex.data = 10;
// ex를 출력하면 값이 변경되어 있다.
ex.Print();
// 아무 키나 누르시면 종료합니다.
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
그러므로 구조체는 null이 존재하지 않습니다.
마지막으로 구조체는 기본구조가 값 형식 참조이기 떄문에 상속이라는 게 존재하지 않습니다.
여기까지 구조체에 대한 설명이었습니다만, 이 구조체라는게 제 생각에는 C++의 흔적(?)이지 않을까 싶습니다. C++에서는 구조체를 사용하면 바이너리를 구조체 형식으로 그대로 읽을 수 있기 때문인데...
C#에서는 그게 되지 않습니다. 그러므로 사실 구조체는 실무에서 전혀 사용하지 않습니다.
왜나햐면 클래스와 사용 방법도 비슷하고 오히려 캡슐화와 클래스의 참조 형식 참조과 값 형식 참조의 차이가 있어서 혼란만 주기 때문에 가독성을 많이 떨어트리는 단점이 있습니다...
여기까지 C#에서의 구조체(struct) 그리고 값 형식 참조(Value type reference)와 참조(포인터) 형식 참조(Reference type reference)에 대한 글이었습니다.
궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.
'Study > C#' 카테고리의 다른 글
[C#] 21. 인덱서(Indexer)를 사용하는 방법 (0) | 2020.07.31 |
---|---|
[C#] 20. 프로퍼티 (Property) (0) | 2020.07.30 |
[C#] 19. 객체 지향(OOP) 프로그래밍의 4대 원칙(캡슐화, 추상화, 상속, 다형성) (0) | 2020.07.28 |
[C#] 18. 열거형(enum)을 사용하는 방법 (2) | 2020.07.27 |
[C#] 16. this와 base의 키워드 (2) | 2020.07.22 |
[C#] 15. 상속 금지 sealed 키워드 (2) | 2020.07.20 |
[C#] 14. 인터페이스(Interface) (0) | 2020.07.15 |
[C#] 13. 추상 클래스(abstract)와 추상 함수(abstract)그리고 가상 함수(virtual) (2) | 2020.07.14 |