클래스와 구조체의 차이
이 질문은 내가 면접을 보러다니던 당시 받았던 질문들이며 내가 제대로 답하지 못했다고 생각하는 것이다. 이 문제에 대해 더 공부하고 잊지 않기 위해 여기에 써둔다.
2026년 수정 안내 이 글은 2012년에 처음 썼는데, 당시 검색으로 모아 정리한 내용 대부분이 사실 C#의 값 타입/참조 타입 설명이었다. C++에는 그대로 적용되지 않는 내용이라 본문을 C++ 기준으로 다시 썼다. 원래 어떻게 잘못 알고 있었는지는 오답노트의 성격상 그대로 남겨둔다.
당시의 문답
- Q. 클래스가 무엇인가?
- A. 같은 성질을 가진 데이터와 함수들의 집합체이다.
- Q. 그럼 구조체 역시도 데이터와 함수를 가질 수 있다. 클래스와 동일하게 구조체로도 만들 수 있는데 왜 클래스를 사용하는가?
- A. 클래스는 상속이 가능하지만 구조체는 불가능하다. → 틀린 답이다.
- Q. 구조체 안에 구조체를 넣을 수 있지 않는가?
- A. 그렇다.
두 번째 답이 틀렸다. C++에서 구조체는 상속을 해줄 수도 있고 받을 수도 있다. 면접관이 파고든 지점도 아마 여기였을 것이다.
C++에서의 진짜 차이
C++ 표준에서 class와 struct의 차이는 딱 두 가지다.
1. 멤버의 기본 접근 지정자
struct S { int a; }; // a는 public
class C { int a; }; // a는 private
2. 기본 상속 접근 지정자
struct D1 : Base { }; // public 상속
class D2 : Base { }; // private 상속
그게 전부다. class C { public: ... };와 struct C { ... };는 완전히 동일한 타입이며, 컴파일 결과도 같다. 심지어 한쪽에서 struct Foo;로 전방 선언하고 다른 쪽에서 class Foo { ... };로 정의해도 동작한다(MSVC는 경고 C4099를 낸다).
따라서 다음은 모두 구조체에서도 된다.
struct Shape {
int id = 0; // 멤버 기본 초기화
explicit Shape(int i) : id(i) {} // 생성자
virtual ~Shape() = default; // 가상 소멸자
virtual double Area() const = 0; // 순수 가상 함수
private: // 접근 지정자
int internal_ = 0;
};
struct Circle : Shape { // 상속
double r;
Circle(int i, double radius) : Shape(i), r(radius) {}
double Area() const override { return 3.141592 * r * r; } // 재정의
};
2012년에 잘못 정리했던 것들
당시 적어둔 목록을 그대로 옮기고, 어디가 틀렸는지 표시한다.
-
클래스와 구조체는 데이터타입을 생성한다는 점에서 유사하다. → 맞다.
-
구조체는 기본접근자가 public인데 클래스의 기본접근자는 private이다. → 맞다. 여기에 기본 상속 접근 지정자 차이까지 더하면 C++에서의 차이는 끝난다.
-
구조체는 데이터의 초기화가 불가능하지만 클래스는 데이터의 초기화가 가능하다.→ 틀렸다. 구조체도 생성자, 멤버 기본 초기화(int x = 0;), 집합체 초기화(S s{1, 2};)를 모두 쓸 수 있다. -
구조체는 value가 복사되지만 클래스는 reference가 복사된다. 따라서 클래스는 얕은 복사, 구조체는 깊은 복사가 일어난다.→ 틀렸고, 용어까지 반대로 썼다. C++에서는 class든 struct든 대입/복사 시 똑같이 값이 복사된다. 참조가 복사되는 건 C#의 참조 타입 이야기다. 그리고 참조를 복사하는 것은 애초에 “얕은 복사”가 아니라 그냥 같은 객체를 가리키는 별칭이다. 오히려 멤버별 값 복사(memberwise copy)가 얕은 복사다. 아래처럼 포인터 멤버가 있으면 포인터 값만 복사되어 두 객체가 같은 대상을 가리킨다.struct Buf { char* p; // 기본 복사 생성자는 포인터 "값"만 복사한다 → 얕은 복사 };깊은 복사가 필요하면 복사 생성자와 복사 대입 연산자를 직접 구현해야 한다. 이건 class냐 struct냐와 아무 상관이 없다.
-
구조체는 상속해줄 수도 상속 받을 수도 없다.→ 틀렸다. 위Circle : Shape예제처럼 잘 된다. C#의 struct 제약을 C++에 그대로 옮긴 것이었다. -
구조체는 참조의 낭비를 막을 수 있으며 데이터에 직접 접근하기 때문에 속도가 더 빠르다.→ 틀렸다. 두 키워드 사이에 성능 차이는 없다. 컴파일러 입장에서 같은 타입이기 때문이다. 성능을 가르는 건 가상 함수 유무(vptr과 간접 호출), 힙 할당 여부, 메모리 레이아웃과 캐시 지역성이지 키워드 선택이 아니다. -
구조체는 함수의 재정의가 안된다.→ 틀렸다. 구조체도virtual선언과override가 된다. 오버로딩도 물론 된다.
값 복사 예제도 다시
당시에는 “클래스는 A를 바꾸면 B도 바뀌고, 구조체는 안 바뀐다”고 적었다. C++에서는 둘 다 B가 바뀌지 않는다.
struct SPoint { int x; };
class CPoint { public: int x; };
SPoint a{1}, b = a; // 값 복사
CPoint c; c.x = 1;
CPoint d = c; // 역시 값 복사
a.x = 99; // b.x는 그대로 1
c.x = 99; // d.x도 그대로 1
참조가 공유되게 하려면 포인터나 참조를 명시적으로 써야 한다.
CPoint* e = &c; // e를 통해 바꾸면 c도 바뀐다
CPoint& f = c; // 마찬가지
이 역시 class든 struct든 동일하다.
그럼 실무에서는 어떻게 나누는가
문법적으로 같으니 관례로 나눈다. 널리 쓰이는 기준은 이렇다.
struct: 불변식(invariant) 없이 데이터를 그냥 묶어놓은 것. 모든 멤버가 public이고 서로 독립적으로 바뀌어도 되는 경우. 패킷 구조체, 설정 값 묶음, 좌표, 타입 트레잇 등.class: 불변식을 유지해야 하는 것. 내부 상태를 감추고 멤버 함수를 통해서만 다루게 하는 경우.
C++ Core Guidelines의 C.2가 정확히 이 기준을 권한다.
댓글 남기기