[C#] struct, class 차이 및 사용법

[C#] struct, class 차이 및 사용법

C#에서 struct와 class의 차이에 대해 알아보겠습니다.

차이점

먼저 구조체와 클래스를 코드로 보겠습니다. 구조체와 클래스로 x, y 좌표를 표현한 코드는 아래와 같습니다.

// 구조체
public struct Point_struct
{
    public int X;
    public int Y;

    public string toString()
    {
        string str = $"({X}, {Y})";
        return str;
    }
}
// 클래스
public class Point_class
{
    public int X;
    public int Y;

    public string toString()
    {
        string str = $"({X}, {Y})";
        return str;
    }
}

코드상으로 보면 크게 차이 없어 보입니다. 하지만 구조체와 클래스는 몇 가지 차이점이 존재합니다.
구조체와 클래스의 대표적인 차이점은 아래 표와 같습니다.

구조체(struct)클래스(class)
형식값 형식 (Value Type)참조 형식 (Reference Type)
메모리 위치스택(Stack)힙(Heap)
상속불가능가능
용도작은 데이터 그룹복잡한 데이터와 동작
성능메모리 할당 및 회수 빠름상대적으로 느림

가장 큰 차이는 형식과, 메모리 위치입니다.

생성자

구조체와 클래스 모두 생성자를 정의할 수 있습니다. 클래스의 경우 생성자를 명시 하지 않을 경우 암시적으로 기본 생성자를 제공해주지만, 구조체는 C# 10 이전 버전에서는 개발자가 기본 생성자를 생성 및 정의할 수 없었습니다. 컴파일러가 기본 생성자를 생성하였고, 필드값을 기본 값으로 초기화 하였습니다. C# 10부터는 기본 생성자를 생성 및 정의 할 수 있으며 필드값을 초기화 할 수 있습니다.

아래 코드는 구조체와 클래스의 생성 및 선언을 한 코드입니다.

public struct Point_struct
{
    public int X;
    public int Y;

    public Point_struct()
    {
        X = 0;
        Y = 0;
    }

    public Point_struct(int x, int y)
    {
        X = x;
        Y = y;
    }

    public string toString()
    {
        string str = $"({X}, {Y})";
        return str;
    }
}

public class Point_class
{
    public int X;
    public int Y;

    public Point_class()
    {
        X = 0;
        Y = 0;
    }

    public Point_class(int x, int y)
    {
        X = x;
        Y = y;
    }

    public string toString()
    {
        string str = $"({X}, {Y})";
        return str;
    }
}

class Program
{
    static void Main(string[] args)
    {
        // 구조체
        Point_struct st1;
        st1.X = 1;
        st1.Y = 2;
        Point_struct st2 = new Point_struct();
        Point_struct st3 = new Point_struct(3, 4);

        Console.WriteLine("st1 :" + st1.toString());
        Console.WriteLine("st2 :" + st2.toString());
        Console.WriteLine("st3 :" + st3.toString());
        Console.WriteLine("");

        // 클래스
        Point_class cls1 = new Point_class();
        Point_class cls2 = new Point_class(3, 4);
        Point_class cls3 = new Point_class(5, 6);

        Console.WriteLine("cls1 :" + cls1.toString());
        Console.WriteLine("cls2 :" + cls2.toString());
        Console.WriteLine("cls3 :" + cls3.toString());
    }
}

실행 하면 아래와 같이 출력 됩니다.

위와 같이 생성된 구조체와 클래스 객체는 각각 스택과 힙 영역에 생성됩니다.

형식 및 전달

구조체는 값 형식으로 전달 되며, 클래스는 참조 형식으로 전달됩니다.
예를 들어 아래와 같이 변수를 더 생성하여 필드의 값을 변경하면 구조체와 클래스의 동작이 다르게 동작하는 것을 볼 수 있습니다.

// 구조체
Point_struct st4 = st1; // 값 복사
Console.WriteLine("변경 전");
Console.WriteLine("st1 :" + st1.toString());
Console.WriteLine("st4 :" + st4.toString());
Console.WriteLine("");

st4.X = 30; // st4의 X만 변경 됨
Console.WriteLine("변경 후");
Console.WriteLine("st1 :" + st1.toString());
Console.WriteLine("st4 :" + st4.toString());
Console.WriteLine("");

// 클래스
Point_class cls4 = cls1; // 참조 복사
Console.WriteLine("변경 전");
Console.WriteLine("cls1 :" + cls1.toString());
Console.WriteLine("cls4 :" + cls4.toString());
Console.WriteLine("");

cls4.X = 30; // cls1의 X도 변경 됨
Console.WriteLine("변경 후");
Console.WriteLine("cls1 :" + cls1.toString());
Console.WriteLine("cls4 :" + cls4.toString());
사용 시 고려사항

구조체와 클래스는 상황에 맞게 사용하는 것이 좋습니다.

  • 구조체
    • 데이터 크기가 작고 간단할 때 (예: 좌표, 색상, 시간 등).
    • 데이터 복사가 성능에 큰 영향을 주지 않을 때
    • 상속이 필요 없는 경우
  • 클래스스
    • 데이터 크기가 크거나 복잡할 때.
    • 데이터가 공유되거나 참조를 통해 전달되어야 할 때
    • 객체 지향 기능(상속, 다형성 등)이 필요한 경우