1. 개요
C++로 개발을 하다보면 다른 클래스, 구조체의 함수 등을 참조해서 개발 할 일이 생깁니다.
이럴때 사용할 수 있는 방식은 전방선언과 헤더 파일 include 이렇게 두가지 방식이 존재합니다.
그렇다면 둘중 아무것이나 사용해도 될까요?
물론 아닙니다.
둘다 컴파일러에게 다른 클래스를 참조할 것을 알려주는 방법들이지만
세부적인 의미는 다릅니다.
그러므로 우리는 두 방법의 차이점을 알고 적절하게 사용하는 것이 중요합니다.
2. 전방선언(Forward Declaration)
전방 선언이란?
전방 선언은 클래스가 있다는 사실만 컴파일러에게 전달하는 것이고 구현이나 내부 정보는 알려주지 않습니다.
class MyClass; // MyClass가 있다는 것만 알려줌
사용 목적
2-1. 헤더 간의 순환 참조(Circular Dependency) 를 방지
순환 참조 : 클래스 A가 클래스 B를 참조하고, 동시에 클래스 B도 클래스 A를 참조하는 상황
예시 코드
// A.h
#include "B.h"
class A {
B b;
};
// B.h
#include "A.h"
class B {
A a;
};
이 경우 컴파일러는 A.h를 처리할 때 B.h를 먼저 포함하고,
B.h는 다시 A.h를 포함하려고 시도하면서 무한 루프에 빠지게 됩니다.
그리고 include guard(#pragma once나 #ifndef)가 있다 해도,
두 클래스가 서로의 정의가 필요한 구조라면 컴파일러는 정의 순서를 찾지 못해서 오류를 발생 시킵니다.
2-2. 컴파일 속도 최적화
hear file로 가져오면 모든 내용을 전부 가져오기 때문에 컴파일 속도가 느려지게 됩니다.
2-3.의존성을 최소화하여 코드 유지보수성 향상
클래스에서 사용되고 있다는 사실만 선언하게 되면 의존성이 줄어들게 됩니다.
가능한 상황
전방 선언은 해당 타입을 포인터나 참조로만 사용할 경우에만 가능합니다.
포인터 변수의 크기는 전부 똑같기 때문에 크기를 몰라도 되어서
포인터를 사용할때만 전방선언으로 처리가 가능합니다.
불가능한 상황
- 객체를 직접 생성할 때
- 해당 클래스의 멤버에 접근하거나, 메서드를 호출할 때
- 상속할 때
- 멤버 변수로 포함할 때
이러한 경우는 크기를 전부 알아야 하기 때문에 전방선언 만으로는 불가능 합니다.
3. 헤더 파일 include
정의
헤더 파일을 include하면, 그 안에 정의된 클래스나 함수, 변수의 전체 내용이 현재 파일에 복사됩니다.
사용 목적
- 객체를 생성하거나 클래스 내부 구조가 필요할 때
- 해당 클래스의 메서드를 호출하거나 상속받을 때
- 멤버 변수로 직접 포함시킬 때
즉 전방 선언과 다르게 객체의 크기를 명확하게 알아야 할 경우에 사용됩니다.
단점
- 다른 헤더도 함께 포함되어 있어 컴파일 시간이 느려짐
- 의존성이 커짐, 유지보수가 어려워질 수 있음
4. 메모리 관점에서 보는 분석
class B;
void TestFunc(B obj); //오류
이렇게 포인터가 아닌 객체 자체를 매개변수로 받게 되면
전방선언으로 할 경우엔 큰 문제가 생긴다.
왜냐하면 컴파일러는 스택에 obj를 올려야 하는데
B라는 class가 몇 바이트짜리이고 어떤 멤버를 가지고 있고 복사 생성자는 무엇인지
알 길이 없다.
결론적으로 메모리 할당도 불가능 하고 호출 코드도 생성 못한다.
컴파일러 입장에서는
전방 선언만 있으면게 된다면
B라는 타입이 존재한다는 사실만 알게되고
B가 몇바이트인지 생성자, 소멸자, 복사연산자등은 전혀 알 수 없다.
즉 메모리 구조를 파악해야 하는 상황에서는 반드시 inclue를 해주어야 한다. (전방선언 x)
'C++' 카테고리의 다른 글
[C++] Smart Pointer (0) | 2025.04.26 |
---|---|
[C++] 스택 풀기(Stack Unwinding) (0) | 2025.04.19 |
[C++] std::map, std::unordered_map (0) | 2025.04.03 |
[C++] const와 constexpr의 차이 (0) | 2025.04.03 |