[C#/.NET] 클래스(Class) 와 구조체(Struct) 의 차이점
본문 바로가기
프로그래밍/C++ \ C#

[C#/.NET] 클래스(Class) 와 구조체(Struct) 의 차이점

by [아마군] 2019. 9. 2.
반응형

 

C# 에서 클래스와 구조체의 차이점에 대해 간단하게 짚어보자.


대부분의 경우 클래스를 사용하는 게 더 익숙할 것이다.

 

우리가 생각하는 객체지향적인 목표에 맞춰 다양한 기능(함수)을 수행해야 하는 경우 클래스를 선언하고 간단하게 자료형(변수) 몇가지를 묶어 하나의 객체로 선언할 때만 구조체를 사용하곤 한다.

 

하지만 엄밀히 말해 구조체에도 함수를 선언해 클래스와 똑같이 사용하는게 가능하며 반대로 클래스를 구조체 처럼 사용해도 문제는 없다.

 

그럼에도 클래스와 구조체는 엄연히 차이점이 존재한다.

 


1. 클래스는 힙(heap) 영역에 할당 되지만 구조체는 스택(stack) 영역에 할당 된다.

 

힙과 스택의 차이점을 간단하게 설명하자면

 

1. 힙은 런타임에 할당되는 영역이며 new 등의 동적 할당 기능을 통해 프로그램 실행 중 필요한 만큼 가변적으로 확보되어 추후 정리를 위해서는 delete 나 가비지 컬렉션 등의 메모리 관리가 필요한 반면,

 

2. 스택은 함수 내에 포함되어 있는 지역 변수 등이 저장되는 영역으로 미리 그 크기를 파악할 수 있기에 컴파일 타임에 결정되며 함수가 종료 되는 시점에서 자동으로 정리되는 영역이다.

 

클래스 객체는 이 중 힙의 영역에 생성되어 메모리 크기에 좀 더 자유로운 대신 가비지 컬렉션의 영향을 받기에 퍼포먼스에 영향을 줄 수 있다.

 

반면 구조체 객체의 경우는 스택 영역에 생성되어 가비지 컬렉션의 영향을 받지 않기에 성능 면에서는 상대적으로 이점이 있지만 메모리 크기 면에서 한정적이라는 단점이 있다.

 


2. 클래스는 참조 타입(Reference Type) 이고 구조체는 값 타입(Value Type) 이다.

 

클래스는 참조 타입이기 때문에 객체를 전달했을 때 그 객체는 항상 원본과 동일하다.

 

즉, 클래스로 생성한 객체를 다른 함수에 전달 했을 때 해당 객체의 멤버 변수의 값을 변경시키면 원본의 변수도 변경 되며 전달받은 함수가 종료되더라도 객체는 계속 유효하다.

 

반면 구조체는 값 타입 이므로 함수를 호출해서 객체를 전달하면 원본과 다른 복사본이 생성된다.

 

때문에 이 객체의 멤버 변수를 변경해도 해당 함수의 스택 영역에 복사된 객체의 변수만 변경 될 뿐 원본은 영향을 받지 않는다.

 

그리고 전달 할 때 참조 타입인 클래스는 자신의 메모리 주소 한개만 넘겨주면 되지만 값을 복사해야 하는 구조체는 자신의 크기 만큼의 스택 공간을 할당하게 되므로 크기가 클수록 메모리 사용량도 늘어난다. (스택은 공간 제약이 있으므로 과도하게 커지면 스택 오버플로우가 발생할 수도 있다)



3. 구조체는 클래스와 달리 상속이 불가능 하다.

 

이 점은 C++ 과 동일하다.

 

상속이 불가능 하기에 기능의 확장에 제약이 있어 아무래도 복잡한 기능에 적용하기는 쉽지 않다. (단, 인터페이스 상속은 가능하다.)

 

다만, 요즘은 OOP 가 예전처럼 만병통치약이 아니라는 인식이 퍼지고 있고 실제로 상속을 최소화 하는 추세이긴 하다.

 


이 외에도 접근 지시자의 기본값이 클래스는 private, 구조체는 public 등의 자잘한 몇가지 차이점이 있긴 하지만 가장 큰 차이는 이 두가지 일 것이다.

 

아무래도 클래스 보다는 구조체를 자주 이용하는 게 가비지 컬렉션의 호출 빈도를 줄이고 힙 할당/해제 보다 스택 할당/해제가 훨씬 빠른 특성 등으로 봤을 때 성능상으로 큰 장점을 가지고 있으므로 적극적으로 사용하는 걸 권한다.

 

다만 아무리 스택 할당/해제가 빠르더라도 용량이 커지면 당연히 주소만 전달하는 클래스보다 더 느려지므로 잘 판단해야 한다.

 

그리고 추가로 구조체 내에 클래스를 멤버 변수로 선언할 경우 해당 구조체는 클래스 처럼 힙 영역에 할당 되는 점을 주의해야 한다.


 

일반적으로 구조체로 사용하기에 적합한 경우는 

  • 객체 내의 멤버 변수가 primitive type(int, float, bool 등) 으로 이루어져 있고
  • 객체의 크기가 작으며
  • 값이 변하지 않고
  • 박싱(boxing)이 자주 일어나지 않는 경우

정도 이다.

 

이 외에는 모두 클래스로 선언해야 한다.

 

정리 하자면 string 같은 클래스를 멤버로 갖지 않는 적은 크기로서 다른 객체에 포함되곤 하는 데이터셋의 경우가 구조체로 선언하기 가장 적합한 케이스이다.

반응형

댓글