C++에서 #include란?
1. #include란 무엇인가?
- 전처리기 지시문 중 하나로, 다른 파일의 내용을 현재 파일로 텍스트 복사함
- 주로 헤더 파일(.h) 을 포함하여 함수, 클래스, 상수 선언을 가져오기 위해 사용
1
2
| #include <iostream> // 표준 라이브러리
#include "MyHeader.h" // 사용자 정의 헤더
|
2. 동작 원리
- 컴파일 과정 중 전처리 단계에서 작동
#include된 파일의 내용이 텍스트로 그대로 삽입됨
전처리 후 예시
1
2
3
4
5
6
7
8
9
10
| // main.cpp
#include "math_utils.h"
int main() {
return square(3);
}
// math_utils.h
int square(int x) {
return x * x;
}
|
전처리 결과:
1
2
3
4
5
6
| int square(int x) {
return x * x;
}
int main() {
return square(3);
}
|
3. include 형식
| 형식 | 의미 | 예시 |
|---|
#include <...> | 시스템 헤더, 표준 라이브러리 | <vector> |
#include "..." | 사용자 정의 헤더 | "MyHeader.h" |
4. 주요 목적
- 코드 재사용 (함수, 클래스 재사용)
- 선언/정의 분리
- 표준 라이브러리 기능 활용
C++에서 #include를 어디에 쓰는 것이 좋을까?
1. 기본 원칙 요약
| include 대상 | 추천 위치 |
|---|
| 클래스, 함수 선언에 필요한 헤더 | .h 파일 |
| 구현에만 필요한 헤더 (지역적 사용) | .cpp 파일 |
2. 헤더(.h)에 include 해야 할 경우
클래스 정의나 함수 시그니처에 직접 사용되는 타입이라면 헤더에 #include 해야 합니다.
1
2
3
4
5
6
7
| // MyClass.h
#include <string> // std::string을 멤버 변수로 사용
class MyClass {
public:
std::string name;
};
|
- 이렇게 하면 이 헤더를 포함하는
.cpp 파일에서도 문제가 없이 사용할 수 있습니다.
3. 소스 파일(.cpp)에 include 해야 할 경우
구현에만 필요한 경우 .cpp에 include 하세요.
1
2
3
4
5
6
7
| // MyClass.cpp
#include "MyClass.h"
#include <iostream> // 구현에만 필요
void MyClass::Print() {
std::cout << name << std::endl;
}
|
- 불필요한 의존성을
.h에 포함시키지 않아도 됩니다.
4. 헤더에 너무 많은 include를 넣으면 생기는 문제점
1. 컴파일 시간 증가
- 헤더 파일이 include되면 해당 내용이 텍스트로 복사되어 들어가므로,
- 많이 include된 헤더는 매번 재처리되어 빌드 속도가 느려집니다.
1
2
3
4
5
6
7
| // A.h
#include <vector>
#include <map>
#include <algorithm>
// B.cpp
#include "A.h"
|
A.h를 포함하면 <vector>, <map>, <algorithm>까지 컴파일해야 하므로 시간이 늘어납니다.
2. 순환 참조(circular include)
- 두 개의 헤더가 서로를 include하면 무한 루프가 발생합니다.
1
2
3
4
5
6
7
8
9
10
11
| // A.h
#include "B.h"
class A {
B* b;
};
// B.h
#include "A.h"
class B {
A* a;
};
|
→ #include 가드나 #pragma once로 방지할 수 있지만, 전방 선언(forward declaration) 을 사용하는 것이 더 좋습니다.
3. 의존성 확산
- A 헤더가 B를 include하고, C가 A를 include하면 C도 B에 의존하게 됩니다.
- → 유지보수 어려움 증가, 의존 관계 복잡해짐
1
2
3
4
5
6
7
8
9
| // A.h
#include "HeavyLibrary.h"
class A {
HeavyType t;
};
// C.cpp
#include "A.h" // 여기서도 HeavyLibrary까지 따라 들어옴
|
→ HeavyLibrary는 C에 필요 없지만 의존하게 되어버림
5. 전방 선언(forward declaration)을 고려하자
1
2
3
4
5
6
7
8
9
10
11
12
| // Bad.h
#include "BigClass.h"
class Bad {
BigClass b;
};
// Good.h
class BigClass; // 전방 선언
class Good {
BigClass* b; // 포인터만 사용할 때 가능
};
|
- 전방 선언을 사용하면
.h에서 include 하지 않아도 되고, .cpp에서만 include 하면 됩니다.
6. 결론
| 상황 | include 위치 |
|---|
| 함수 인자, 멤버 변수로 사용 | .h |
| 구현 내부에서만 사용 | .cpp |
| 포인터/참조만 쓸 경우 | .h에서 전방 선언 후 .cpp에 include |
| 빌드 시간 최적화 원할 때 | 필요 최소한만 .h에 포함 |
- include는 꼭 필요한 곳에만, 가급적 .cpp에
- 전방 선언을 적극 활용
- 헤더는 작고 독립적으로 유지하는 것이 좋음