
C++에서
struct와class는 거의 같은 기능을 가집니다.
하지만 이 “거의” 안에 중요한 차이가 숨어 있습니다.
바로 기본 접근제한자와 기본 상속제한자입니다.이 작은 차이는 단순한 문법 차원이 아니라, 코드의 의도(데이터 중심 vs 캡슐화 중심) 와 설계 철학을 드러내는 중요한 신호입니다.
따라서, 이번 글에서는
struct와의 차이점을 정리해보겠습니다.
struct S {
int x; // 기본적으로 public
void hello(); // 기본적으로 public
};
class C {
int x; // 기본적으로 private
void hello(); // 기본적으로 private
public:
C(); // 명시적으로 공개해야 함
};
struct는 기본적으로 모든 멤버가 public,class는 기본적으로 모든 멤버가 private입니다.struct Base {};
struct Derived : Base { }; // 기본적으로 public 상속
class Base2 {};
class Derived2 : Base2 { }; // 기본적으로 private 상속
struct는 상속 시 public 상속이 기본,class는 private 상속이 기본입니다.C++에서 두 키워드는 역할이 아니라 의도(intent) 를 표현합니다.
즉, “이 타입이 어떤 목적으로 만들어졌는가?”에 따라 선택이 갈립니다.
struct를 사용하는 경우“데이터를 담는 용도”, 즉 값 중심 타입일 때.
- DTO, Record, Value Object 등 단순한 데이터 전달 구조체
- 알고리즘에서 사용하는 보조 구조 (
Edge,Node,Point등)- 공개 필드가 자연스러운 데이터형
struct Edge {
int to;
int cost;
};
struct Point {
int x, y;
double length() const noexcept {
return std::sqrt(1.0 * x * x + 1.0 * y * y);
}
};
📌 데이터가 중심이고, 캡슐화보단 직관성이 우선인 경우 적합합니다.
class를 사용하는 경우“행동과 정책”, 즉 캡슐화 중심 타입일 때.
- 내부 상태를 보호하고, 외부엔 인터페이스만 노출하고 싶을 때
- 불변성, 유효성 검사, 비즈니스 로직 등이 필요한 경우
- 수명/리소스 관리(RAII)나 상속, 다형성이 중요한 경우
class BankAccount {
public:
explicit BankAccount(int initial);
void deposit(int amount);
void withdraw(int amount);
int balance() const noexcept;
private:
int balance_;
};
📌 데이터 보호, 정책 제어, 로직 관리가 목적이라면 class가 자연스럽습니다.
| 상황 | 추천 키워드 | 이유 |
|---|---|---|
| 데이터 구조, DTO, 레코드 | struct | 멤버가 공개되는 것이 자연스럽고 간단 |
| 도메인 로직, 상태 보유 객체 | class | 캡슐화 및 무결성 유지 용이 |
| 상속 기반 설계 (인터페이스 등) | class | 접근 제어와 다형성 관리 명확 |
| 단순 데이터 묶음 + 연산자 오버로딩 | struct | 값 기반 표현에 적합 |
structstruct Graph {
int N{};
std::vector<std::vector<int>> adj;
std::vector<char> visited;
explicit Graph(int n = 0)
: N(n), adj(n + 1), visited(n + 1, 0) {}
void addEdge(int u, int v) {
adj[u].push_back(v);
adj[v].push_back(u);
}
void bfs(int start) {
std::queue<int> q;
visited[start] = 1;
q.push(start);
while (!q.empty()) {
int u = q.front(); q.pop();
for (int v : adj[u])
if (!visited[v])
visited[v] = 1, q.push(v);
}
}
};
📌 데이터와 간단한 연산이 한 덩어리로 존재.
📌 필드 공개가 자연스럽고, 테스트도 간단.
따라서, struct 적합.
classclass GraphService {
public:
explicit GraphService(int n) : N_(n), adj_(n + 1) {}
void addEdge(int u, int v) {
adj_[u].push_back(v);
adj_[v].push_back(u);
}
int components() {
std::vector<char> vis(N_ + 1, 0);
int cnt = 0;
for (int i = 1; i <= N_; ++i)
if (!vis[i]) bfs(i, vis), ++cnt;
return cnt;
}
private:
int N_;
std::vector<std::vector<int>> adj_;
void bfs(int s, std::vector<char>& vis) {
std::queue<int> q; vis[s] = 1; q.push(s);
while (!q.empty()) {
int u = q.front(); q.pop();
for (int v : adj_[u])
if (!vis[v]) vis[v] = 1, q.push(v);
}
}
};
📌 내부 상태를 숨기고, 명확한 API로 관리.
따라서, 캡슐화 중심 → class 적합.
| 오해 | 진실 |
|---|---|
“struct는 함수 정의 불가” | ❌ C++에선 가능. 생성자, 소멸자, 오버로딩, 상속 모두 지원 |
“struct는 C 전용 문법” | ❌ C++에선 public class의 문법적 설탕(Syntactic Sugar)에 가깝습니다 |
| “성능 차이가 있다” | ❌ 없습니다. 선택 기준은 오직 의도와 설계 철학입니다 |
📌 문법적 설탕(Syntactic Sugar)?
“이미 있는 기능을 더 간결하고 편하게 쓰도록 만든 문법”이라는 뜻입니다.
즉, 새로운 기능을 추가하는 건 아니고, 같은 기능을 더 보기 쉽게 표현한 문법적 편의를 말합니다.예를 들어,
“설탕”이라는 말처럼 코드를 더 읽기 좋고 쓰기 쉽게 만드는 ‘감미료’ 같은 존재를 의미합니다. 내부적으로는 완전히 동일한 동작을 하지만, 개발자는 더 짧고 직관적인 코드를 쓸 수 있게 해줍니다.
struct vs C++의 structC와 C++에서 struct라는 키워드는 같지만, 완전히 다른 목적과 철학을 가집니다.
C에서는 “데이터의 묶음”에 불과하지만, C++에서는 **“데이터 + 행동을 함께 표현하는 객체”** 로 발전했습니다.
| 항목 | C의 struct | C++의 struct |
|---|---|---|
| 목적 | 단순한 데이터 묶음 (메모리 레이아웃 중심) | 데이터 + 행동을 함께 표현하는 타입 |
| 멤버 함수 | ❌ (불가) | ✅ (정의 가능) |
| 생성자/소멸자 | ❌ | ✅ |
| 접근 제어 | ❌ (전부 공개) | ✅ (public, private, protected) |
| 상속/다형성 | ❌ | ✅ |
| 연산자 오버로딩 | ❌ | ✅ |
| 선언 방식 | struct Point p; 필수 | Point p; 가능 |
| 템플릿/네임스페이스 | ❌ | ✅ |
📌 한 줄 요약
struct = 데이터 그릇 struct = 사실상 public classC에서의 struct
// C 언어
#include <stdio.h>
struct Point {
int x;
int y;
};
// 함수는 구조체 밖에서 따로 정의
void move(struct Point* p, int dx, int dy) {
p->x += dx;
p->y += dy;
}
int main() {
struct Point p = { 1, 2 };
move(&p, 3, 4);
printf("x = %d, y = %d\n", p.x, p.y); // 출력: x = 4, y = 6
}
📌 C에서는
struct는 단순히 데이터 필드들의 묶음이며,struct 키워드를 생략할 수 없습니다. (struct Point p;)즉, 구조체는 메모리 레이아웃(데이터의 집합) 자체를 표현합니다.
C++에서의 struct
// C++ 언어
#include <iostream>
#include <cmath>
struct Point {
int x;
int y;
// 생성자
Point(int x, int y) : x(x), y(y) {}
// 멤버 함수
void move(int dx, int dy) {
x += dx;
y += dy;
}
// 멤버 함수 (행동 + 상태)
double length() const {
return std::sqrt(1.0 * x * x + 1.0 * y * y);
}
};
int main() {
Point p{1, 2}; // struct 키워드 생략 가능
p.move(3, 4);
std::cout << p.x << ", " << p.y << " → length = " << p.length() << '\n';
}
📌 C++에서는
struct 안에 생성자, 멤버 함수, 연산자 모두 정의 가능하며,struct 없이 객체 생성 가능합니다.public class처럼 동작합니다.| 관점 | C | C++ |
|---|---|---|
| 언어 철학 | 데이터 중심 (절차적) | 객체 중심 (캡슐화) |
| 메모리 레이아웃 | 단순 필드 나열 | 동일하지만 접근제어자, 가상함수 등 추가 기능 |
| 함수 호출 방식 | move(&p, dx, dy) | p.move(dx, dy) (객체 지향적) |
| 코드 응집도 | 낮음 (데이터와 함수 분리) | 높음 (데이터와 행동 결합) |
| 확장성 | 구조체마다 별도 함수 필요 | 상속, 오버로딩 등 재사용 가능 |
즉,
C에서는 “데이터를 전달하기 위한 구조체”였던 것이,
C++에서는 “행동을 포함하는 객체”로 확장된 것입니다.
struct는 단순히 데이터 묶음이며, 함수는 외부에 존재합니다.struct는 사실상 멤버가 public인 클래스로, 객체지향 기능을 모두 가집니다.Q1.
struct에 private 멤버를 넣어도 되나요?
A. 네. C++에서는 접근제어자를 지원합니다. 단지 기본이 public일 뿐입니다.
Q2. 성능 차이는 전혀 없나요?
A. 없습니다. 메모리 구조나 실행 속도는 동일합니다. 선택은 “의도” 문제입니다.
Q3. 사용하는 기준이 다른가요?
A. 맞습니다. 보통 “데이터 중심은 struct, 로직 중심은 class”로 정합니다.
struct와 class는 문법적으로 거의 동일하지만, 기본 접근제한자와 상속제한자가 다릅니다.structclassstruct는 단순한 데이터 묶음, C++의 struct는 사실상 public class.결국 중요한 건 “이 타입이 어떤 역할을 하는가” 입니다.
코드의 의도를 명확히 표현하는 선택이,
협업과 유지보수의 품질을 결정합니다.
| 구분 | struct (C++) | class (C++) |
|---|---|---|
| 기본 접근제한자 | public | private |
| 기본 상속제한자 | public | private |
| 멤버 함수 / 생성자 / 소멸자 | 지원됨 | 지원됨 |
| 상속 / 다형성 | 지원됨 | 지원됨 |
| 주요 용도 | 데이터 중심 구조체 (Record, DTO, Point 등) | 캡슐화 중심 객체 (도메인 로직, 상태 관리 등) |