컴퓨터공학/C++

[C++] 전방 선언

Pyxis 2024. 11. 5. 17:15

[ C++ : 전방 선언 ]

 

class를 만들면서 문제가 되기 시작하는 것은 Player class내에서 다른 class를 멤버 변수로 갖게 되는 것.

일반 객체로 갖고 있거나, 포인터로 갖고 있을 수 있다.

// Player.h

class Player
{
/* ... */

Monster target;
Montser* target2;
}

 

Player의 설계도를 완성하려면, Monster의 크기를 알아야하므로 Monster.h를 include해야 한다.

Player를 만들기 전에, Monster를 만들어야 하는 것. 의존성이 생긴 것이다.

 

반대로, Monster*를 들고 있다고 생각해보자.

이전과 달리, 포인터이므로 Monster.h가 없더라도 알 수 있다. 본질적으로 Monster*는 주소를 담는 바구니이기 때문이다.

이제, Monster가 등장할 것이라고 미리 알려주기 위해 .h 파일 상단에서 class Monster;로 전방선언을 해주자.

Player와 Monster와의 이존성이 끊어진 것이다.

 

void Attack()
{
	target2->hp = 0;
}

이제, Player.cpp 파일의 어떤 함수에서 target2의 멤버 변수에 접근 한다고 가정해보자.

Monster* target2의 주소를 타고가서, 접근하기 위해 설계도를 참고해서 hp가 해당 메모리 주소로부터 얼마만큼 떨어져 있는지 확인해야 한다.

이는 함수에도 동일한데, 함수의 시그니쳐까지는 알아야한다.

결론은 전방선언을 했더라도 cpp 파일에서 해당 포인터에 대해서 접근할 일이 있다면, 해당 헤더 파일을 include해줘야 하는 것.

→ #include "Monster.h"

이제 .h인 헤더파일에서는 의존성이 있는 포인터의 경우, 함수 구현부를 전부 .cpp 파일에 작성하는 것이 낫다.

그렇지 않으면 클래스 정보가 필요하므로 전방선언을 이용하지 못하고, 해더파일에서 일일이 include해줘야 한다.

이는 두 파일간의 종속성이 생기는 것인데, 결국 컴파일 시간의 증가를 불러온다.

 

다음은 Q&A의 요약.

cpp 단위로 빌드가 되어 오브젝트 파일이 각기 만들어진 후, 다시 이를 링크 단계에서 합치고 최종 실행 파일이 만들어지는데요.
A.cpp에서 다른 헤더(B.h)를 include하면, 당장은 선언 형식만 알려주고 나중에 링크 단계에서 실제 구현부가 있는 주소랑 매핑해줍니다.
이 때 B.h에 변화가 생기더라도 A는 큰 영향을 받지 않고 단지 매핑된 주소만 바꿔치기 해주면 됩니다.
반면 A.h에서 다른 헤더(B.h)를 include하면, 둘 사이의 종속성이 생기게 되어 B.h에 변화가 생기면 A도 다시 빌드가 되어야 합니다.
이게 나비효과처럼 빠르게 불어날 수 있기 때문에, 기본적으로 [항상 전방선언을 사용하되, 상속 구조와 같이 정말 어쩔 수 없는 상황에서만 헤더에서 헤더를 포함] 하는 규칙을 일상화 해야 합니다.

 

 

 

 

 

 

[ Reference ]

Rookiss, Part1 C++ 입문

 

 

 

 

'컴퓨터공학 > C++' 카테고리의 다른 글

[C++] 캐스팅 4가지  (0) 2024.11.09
[C++] std::move()  (0) 2024.11.09
[C++] 템플릿 기초  (0) 2024.11.05
[C++] 타입 변환과 얕은 복사, 깊은 복사  (0) 2024.11.05
[C++] Virtual function performance  (1) 2024.11.03