헤더 파일(C++)

변수, 함수, 클래스 등과 같은 프로그램 요소의 이름을 선언해야 사용할 수 있습니다. 예를 들어 먼저 'x'를 선언하지 않고는 작성 x = 42 할 수 없습니다.

int x; // declaration
x = 42; // use x

이 선언은 요소가 요소int인지, 함수double인지, 아니면 다른 요소인지를 컴파일러에 class 알려줍니다. 또한 사용되는 모든 .cpp 파일에서 각 이름을 직접 또는 간접적으로 선언해야 합니다. 프로그램을 컴파일할 때 각 .cpp 파일은 컴파일 단위로 독립적으로 컴파일됩니다. 컴파일러는 다른 컴파일 단위에서 선언된 이름을 알지 않습니다. 즉, 클래스 또는 함수 또는 전역 변수를 정의하는 경우 이를 사용하는 각 추가 .cpp 파일에 해당 항목의 선언을 제공해야 합니다. 해당 항목의 각 선언은 모든 파일에서 정확히 동일해야 합니다. 링커가 모든 컴파일 단위를 단일 프로그램에 병합하려고 할 때 약간의 불일치로 인해 오류 또는 의도하지 않은 동작이 발생합니다.

오류 가능성을 최소화하기 위해 C++는 헤더 파일을 사용하여 선언을 포함하는 규칙을 채택했습니다. 헤더 파일에서 선언을 만든 다음 모든 .cpp 파일 또는 해당 선언이 필요한 다른 헤더 파일에서 #include 지시문을 사용합니다. #include 지시문은 컴파일하기 전에 헤더 파일의 복사본을 .cpp 파일에 직접 삽입합니다.

참고 항목

Visual Studio 2019에서 C++20 모듈 기능은 헤더 파일을 개선하고 최종적으로 대체하는 기능으로 도입되었습니다. 자세한 내용은 C++의 모듈 개요를 참조하세요.

예시

다음 예제에서는 클래스를 선언한 다음 다른 소스 파일에서 사용하는 일반적인 방법을 보여 있습니다. 헤더 파일 my_class.h로 시작하겠습니다. 클래스 정의가 포함되어 있지만 정의가 불완전합니다. 멤버 함수 do_something 가 정의되지 않았습니다.

// my_class.h
namespace N
{
    class my_class
    {
    public:
        void do_something();
    };

}

다음으로 구현 파일(일반적으로 .cpp 또는 유사한 확장명 포함)을 만듭니다. my_class.cpp 파일을 호출하고 멤버 선언에 대한 정의를 제공합니다. .cpp 파일의 이 시점에서 my_class 선언을 삽입하기 위해 "my_class.h" 파일에 대한 std::cout지시문을 추가하고 #include 선언을 끌어오도록 포함합니다<iostream>. 따옴표는 원본 파일과 동일한 디렉터리의 헤더 파일에 사용되며 꺾쇠 괄호는 표준 라이브러리 헤더에 사용됩니다. 또한 많은 표준 라이브러리 헤더에는 .h 또는 다른 파일 확장명이 없습니다.

구현 파일에서 필요에 따라 문을 사용하여 using "n::" 또는 "std:"로 "my_class" 또는 "cout"의 모든 멘션 한정하지 않아도 됩니다. 헤더 파일에 문을 넣지 using 마세요.

// my_class.cpp
#include "my_class.h" // header in local directory
#include <iostream> // header in standard library

using namespace N;
using namespace std;

void my_class::do_something()
{
    cout << "Doing something!" << endl;
}

이제 다른 .cpp 파일에서 사용할 my_class 수 있습니다. 컴파일러가 선언을 끌어오도록 헤더 파일을 #include. 컴파일러에서 알아야 할 모든 것은 my_class 공용 멤버 함수가 호출 do_something()된 클래스라는 것입니다.

// my_program.cpp
#include "my_class.h"

using namespace N;

int main()
{
    my_class mc;
    mc.do_something();
    return 0;
}

컴파일러가 각 .cpp 파일을 .obj 파일로 컴파일한 후 링커에 .obj 파일을 전달합니다. 링커가 개체 파일을 병합하면 my_class 대한 정의가 하나만 발견됩니다. my_class.cpp용으로 생성된 .obj 파일에 있으며 빌드가 성공합니다.

가드 포함

일반적으로 헤더 파일에는 단일 .cpp 파일에 여러 번 삽입되지 않도록 하는 include 가드 또는 #pragma once 지시문이 있습니다.

// my_class.h
#ifndef MY_CLASS_H // include guard
#define MY_CLASS_H

namespace N
{
    class my_class
    {
    public:
        void do_something();
    };
}

#endif /* MY_CLASS_H */

헤더 파일에 넣을 내용

헤더 파일은 잠재적으로 여러 파일에 포함될 수 있으므로 동일한 이름의 여러 정의를 생성할 수 있는 정의를 포함할 수 없습니다. 다음은 허용되지 않거나 매우 나쁜 사례로 간주됩니다.

  • 네임스페이스 또는 전역 범위의 기본 제공 형식 정의
  • 인라인이 아닌 함수 정의
  • 비 const 변수 정의
  • 집계 정의
  • 명명되지 않은 네임스페이스
  • using 지시문

using 지시문을 사용하면 반드시 오류가 발생하는 것은 아니지만 해당 헤더를 직접 또는 간접적으로 포함하는 모든 .cpp 파일의 범위로 네임스페이스를 가져오기 때문에 잠재적으로 문제가 발생할 수 있습니다.

샘플 헤더 파일

다음 예제에서는 헤더 파일에서 허용되는 다양한 종류의 선언 및 정의를 보여 줍니다.

// sample.h
#pragma once
#include <vector> // #include directive
#include <string>

namespace N  // namespace declaration
{
    inline namespace P
    {
        //...
    }

    enum class colors : short { red, blue, purple, azure };

    const double PI = 3.14;  // const and constexpr definitions
    constexpr int MeaningOfLife{ 42 };
    constexpr int get_meaning()
    {
        static_assert(MeaningOfLife == 42, "unexpected!"); // static_assert
        return MeaningOfLife;
    }
    using vstr = std::vector<int>;  // type alias
    extern double d; // extern variable

#define LOG   // macro definition

#ifdef LOG   // conditional compilation directive
    void print_to_log();
#endif

    class my_class   // regular class definition,
    {                // but no non-inline function definitions

        friend class other_class;
    public:
        void do_something();   // definition in my_class.cpp
        inline void put_value(int i) { vals.push_back(i); } // inline OK

    private:
        vstr vals;
        int i;
    };

    struct RGB
    {
        short r{ 0 };  // member initialization
        short g{ 0 };
        short b{ 0 };
    };

    template <typename T>  // template definition
    class value_store
    {
    public:
        value_store<T>() = default;
        void write_value(T val)
        {
            //... function definition OK in template
        }
    private:
        std::vector<T> vals;
    };

    template <typename T>  // template declaration
    class value_widget;
}