[CopyRogue] 소스 파일(.cpp), 헤더 파일(.h)

(소스 파일헤더 파일)

  • 간단 설명:
    • 파일은 여러 개가 존재합니다: 꼭 c++이 아니더라도 프로그래밍을 할 때, 기능을 분리하는 것은 객체 지향 프로그래밍이라면 반드시 지켜야 할 수칙 중 하나입니다. 기능을 넣고 빼기도 쉬워지고 다른 기능에 영향을 덜 주게 되기 때문입니다. 그렇기에 하나의 cpp 파일에 모든 코드를 넣을 수도 있긴 하지만 여러 개의 cpp 파일을 만들어 기능을 분리하고 파일을 관리하기 편하도록 설계합니다.
    • 컴파일러는 2개 이상의 cpp 파일을 동시에 알 수 없습니다: 그런데 문제는 cpp 파일을 여러개로 만들어서 나눠놓으면 컴파일러가 어느 cpp 파일에서 또 다른 cpp 파일에 있는 메서드를 발견했을 때 발생합니다. BangGe.cpp 파일에 Write() 메서드가 있고, Main.cpp 파일에서 BangGe.cpp 파일의 Write() 메서드를 사용한다면, Main.cpp 파일에서 컴파일러는 BangGe.cpp 파일한테는 눈길도 주지 않고 "Main.cpp 파일에는 Write() 메서드가 없어!"라는 말만 반복합니다.
    • 메서드가 존재한다는 것을 컴파일러에게 알려줘야 합니다: 저희는 안타깝게도 말로 이 갈등을 해결하여 메서드가 있다는 것을 알려줄 수 없습니다. 그럼 어쩔 수 없이 Main.cpp 파일에 Write() 메서드를 선언해야 할까요? 예, 그렇습니다. 하지만 이렇게 되면 당연히 맨 처음에 말한 기능의 분리라는 기본적인 원칙을 어기게 되기도 하고, Main.cpp 파일이 아닌 다른 파일에서 또 그 함수를 쓴다면 직접 복사, 붙여 넣기를 해야하는데, 말만 들어도 이건 아니다 싶기 때문에 특별한 방법을 사용합니다.
    • 컴파일러를 이용하기: 컴파일러는 번역 단위(cpp 파일과 그 안에 #include 된 헤더 파일)로만 컴파일 할 수 있습니다. 하지만 이런 컴파일러를 다그치기 보다는, 이용하는 것이 편합니다. 컴파일러는 절대로 알아서 증거를 찾지 못합니다. 하지만 그것은 동시에 컴파일러에게 증거를 준다면, 그 증거가 참일지 거짓일지 컴파일러는 분별할 수 없다는 소리이기도 합니다.
    • 증거를 만들기: 제가 예시로 든 상황에서 컴파일러가 원하는 증명은 간단합니다. 'Write() 메서드가 존재한다.' 라는 것이죠. 제가 아까 저희는 안타깝게도 말로 갈등을 해결할 수 없다고 했는데, 그렇다면 컴파일러와 대화할 수 있는 코드를 통하여 컴파일러에게 말을 전할 수 있습니다. "Write() 메서드 있다."라는 증거가 있다면 컴파일러는 믿습니다. 그리고 그 증거가 담긴 코드가 헤더 파일입니다.
    • 구현: 컴파일러는 헤더 파일만 있어도 아무런 오류 메세지를 띄우지 않고 작업을 끝냅니다. 있다는 말만 하고 실제로는 구현하지 않았더라도 말입니다. 하지만 컴파일러가 자신의 일을 마치고 링커에게 코드를 전달하면, 링커는 자신의 이름처럼 코드를 연결하여 실제로 실행시킬 수 있는 .exe 파일을 만듭니다. 그런데 만들던 중 헤더 파일에 있는 메서드가 실제로 구현되어 있지 않다면 오류 메시지를 띄웁니다. 하지만 이 오류 메시지는 고마운 오류 메시지입니다. 컴파일러는 직접 찾아보지도 않고 하나의 번역 단위로만 판단하여 오류 메시지를 띄우는 반면, 링커는 정말 구현되지 않았을 경우에만 오류 메시지를 띄우기 때문입니다.
  • 코드 설명: 예제 코드는 게임의 렌더링, 업데이트, 시작 등을 호출해주는 프로그램의 중심인 Core로 가져왔습니다. 지금 내용은 크게 중요하지 않으니 넘기고 헤더 파일을 먼저 설명해 보겠습니다.
    • 헤더 파일의 요소: 
      • #pragma once: 보통 헤더의 가장 첫 줄이 #pragma once 일 텐데, 다시 말하지만 컴파일러는 번역 단위로 컴파일하기 때문에 헤더 파일을 만들 뿐만 아니라 불러오기를 해야 합니다. 불러오는 방법은 간단합니다. #include라는 전처리 지시문은 특정 헤더 파일의 코드를 통째로 복사, 붙여 넣기 해줍니다. 하지만 이런 방식을 사용하면 A.h 헤더 파일을 #include 한 B.h 헤더 파일과 A.h 파일을 #include 하여 결과적으로 A.h 헤더 파일 2개와 B.h 헤더 파일 1개를 가지고 있는 버그 덩어리 파일이 생기지 않게 같은 헤더가 하나의 번역 단위에 두 번 이상 포함되지 않게 해주는 전처리 지시문입니다.
      • 메서드의 프로토타입: 아래의 코드를 보시면 Core(), _Core() 같은 메서드가 보입니다. 그런데 구현, 즉, 중괄호는 보이지 않습니다. 아까 헤더 파일은 그냥 증거를 담은 코드라고 설명했습니다. 즉 "Write() 메서드가 있다"라는 증거에 굳이 "노트북을 켜서 크롬을 열고 티스토리에 들어가서 어쩌고를 한다"라는 첨언은 필요 없기 때문입니다. 그래도 구현이 불가능한 것은 아닌데, 헤더 파일에서 메서드를 구현하면 문제가 생깁니다. 아래의 코드를 보시면 아시겠지만 일단 저렇게 메서드의 프로토타입, 즉 깔끔하게 선언만 해놓은 상태에서 메서드를 구현하면 가독성도 떨어질뿐더러, 다음에 설명할 내용이지만 #include를 사용하였을 때 메서드의 구현이 2개 이상이 될 수도 있기 때문입니다.
      • 클래스, 구조체, 열거형(enum) 선언: 방금 설명한 메서드 프로토타입 말고도 필드나 인라인 메서드(바로 앞에서 구현하면 안된다고 했지만, 간단한 메서드는 인라인 메서드를 사용하여 헤더 파일에서 구현할 수 있다는 것 정도만 설명하겠습니다)와 같은 멤버 변수와 멤버 함수를 선언해 클래스와 구조체를 선언할 수 있습니다. 그리고 사용할 열거형도 헤더에서 선언할 수 있습니다.
      • 그 외: 그 외에도 헤더에는 상수, 타입, 네임스페이스, 매크로, 템플릿 등을 선언, 정의할 수 있습니다.  
    • 소스 파일의 요소: 소스 파일에선 헤더 파일을 #include 하여 붙여 넣은 선언을 토대로 구현을 하는, 말로는 간단한 코드를 쓰게 됩니다. 
더보기

헤더 파일 예시

#pragma once

class Core
{
public:
	Core();
	~Core();
public:
	void Run();
private:
	void Init();
	void Update();
	void Render();

private:
	bool m_isRunning = true;
};

 

더보기

소스 파일 예시

#include "Core.h"
#include "Console.h"
#include "Defines.h"
#include "TitleScene.h"
#include "GameScene.h"
#include "SceneManager.h"

Core::Core()
{
	SceneManager::GetInst()->RegisterScene("TitleScene",std::make_unique<TitleScene>());
	SceneManager::GetInst()->RegisterScene("GameScene", std::make_unique<GameScene>());
	SceneManager::GetInst()->ChangeScene("TitleScene");
}

void Core::Init()
{
	SetCursorVisual(false, 1);
	SetConsoleSettings(1280, 720, false, L"Copy Rogue");
	SetLockResize();
}

void Core::Update()
{
	SceneManager::GetInst()->Update();
}

void Core::Render()
{
	SceneManager::GetInst()->Render();
}

Core::~Core()
{
	SceneManager::GetInst()->DestroyInst();
}

void Core::Run()
{
	Init();
	while (m_isRunning)
	{
		Update();
		Render();
		FrameSync(60);
	}
}
  • 관련 개념: 전처리 지시문, 빌드
  • C#과의 차이점: C#의 컴파일러는 c++의 컴파일러와 다른데, c++의 컴파일러는 번역 단위로 컴파일하는 반면 C#의 컴파일러는 프로젝트 전체를 한 번에 컴파일하기 때문에 파일 간의 경계가 거의 없고 따라서 헤더 파일도 없습니다.
  • 한줄평: C#과 c++이 비슷한 것 같으면서도 이런 사소한 차이 때문에 차이점이 많이 생기니 공부하는 입장에서는 죽을 맛인 것 같습니다.

'C++ > CopyRogue' 카테고리의 다른 글

[CopyRogue] *, & 키워드  (0) 2026.02.13