이 Step에서 다루는 것

  • 클래스가 커지기 시작하면 .h/.cpp로 나누는 이유
  • “선언(인터페이스)”과 “정의(구현)”를 분리해서 의존성/빌드 시간/협업 충돌을 줄이는 방법
  • 멤버 함수 정의에서 Player::가 왜 필요한지

학습 목표

  • .h에는 무엇을 두고, .cpp에는 무엇을 두는지 말로 설명할 수 있다.
  • “선언만 있고 정의가 없다”가 링크 에러로 이어지는 이유를 설명할 수 있다.
  • 헤더를 “가볍게” 유지하는 기본 원칙 3가지를 말할 수 있다.

헤더 vs CPP

  • 헤더(.h): “이 클래스/함수가 있다”를 알리는 선언(Declaration) 중심
    • 클래스 정의(멤버 변수/함수 시그니처)
    • 상수/열거형/필요 최소 선언
  • 소스(.cpp): “실제로 어떻게 동작하는지”를 적는 정의(Definition) 중심
    • 멤버 함수 구현
  • 멤버 함수 구현에서 Player::Attack()처럼 Player::를 붙이는 이유:
    • “이 함수는 Player 클래스의 멤버 함수다”를 명확히 연결(스코프 지정)

권장 구조

  • 한 파일에 모든 코드를 넣지 말고 클래스(또는 모듈) 단위로 분리합니다.
  • 보통 Player.h(선언) + Player.cpp(정의) 쌍으로 관리하고,
    사용하는 쪽에서 #include "Player.h"로 “선언”을 가져옵니다.

파일 분리 구조(최소 예시)

Player.h   (선언/인터페이스)
Player.cpp (정의/구현)
Main.cpp   (사용)

Player.h

#pragma once

class Player {
public:
    void Attack();
    void Die();
    void HealMe(int value);

private:
    int _hp = 0;
    int _attack = 0;
    int _defence = 0;
};

헤더 작성 팁:

  • 헤더에는 using namespace std;를 두지 않는 게 안전합니다(전역 오염).
  • <iostream> 같은 무거운 include도 가능하면 .cpp로 옮깁니다.

Player.cpp

#include "Player.h"
#include <iostream>

void Player::Attack() { std::cout << "Attack" << '\n'; }
void Player::Die() { std::cout << "Die" << '\n'; }
void Player::HealMe(int value) {
    _hp += value;
    std::cout << "Heal " << _hp << '\n';
}

Main.cpp (사용)

#include "Player.h"

int main()
{
    Player p;
    p.HealMe(10);
    p.Attack();
    return 0;
}

자주 터지는 에러(파일 분리 초보 필수)

  • 컴파일 에러(선언되지 않음): #include "Player.h"를 안 했거나, 헤더에 선언이 없음
  • 링크 에러(외부 기호를 찾을 수 없음): 선언은 했는데 .cpp에 정의(구현)가 없거나, 프로젝트에 .cpp가 포함되지 않음
  • 시그니처 불일치: 헤더와 cpp의 함수 모양(매개변수/리턴/네임스페이스)이 조금이라도 다름

체크 질문 (스스로 답해보기)

  • 왜 헤더에 <iostream>을 넣는 걸 조심해야 할까?
  • 헤더에 using namespace std;를 두면 어떤 문제가 생길 수 있을까?
  • “선언만 있고 정의가 없음”이 컴파일이 아니라 링크에서 터지는 이유는?

profile
李家네_공부방

0개의 댓글