Szukaj…


Uwagi

W C ++, podobnie jak w C, kompilator i proces kompilacji C ++ korzysta z preprocesora C. Zgodnie z instrukcją GNU C Preprocessor plik nagłówkowy jest zdefiniowany następująco:

Plik nagłówkowy to plik zawierający deklaracje C i definicje makr (patrz Makra), który może być współużytkowany przez kilka plików źródłowych. Zażądasz użycia pliku nagłówkowego w swoim programie, dołączając go do dyrektywy C w sprawie wstępnego przetwarzania „#include”.

Pliki nagłówkowe służą dwóm celom.

  • Pliki nagłówków systemowych deklarują interfejsy do części systemu operacyjnego. Uwzględniasz je w swoim programie, aby dostarczyć definicje i deklaracje potrzebne do wywoływania wywołań systemowych i bibliotek.
  • Twoje własne pliki nagłówkowe zawierają deklaracje interfejsów między plikami źródłowymi twojego programu. Za każdym razem, gdy masz grupę powiązanych deklaracji i definicji makr, z których wszystkie lub większość jest potrzebna w kilku różnych plikach źródłowych, dobrym pomysłem jest utworzenie dla nich pliku nagłówka.

Jednak w przypadku samego preprocesora C plik nagłówkowy nie różni się od pliku źródłowego.

Schemat organizacji plików nagłówkowych / źródłowych jest po prostu silną i standardową konwencją ustanowioną przez różne projekty oprogramowania w celu zapewnienia rozdziału między interfejsem a implementacją.

Chociaż nie jest to formalnie egzekwowane przez sam standard C ++, wysoce zalecane jest przestrzeganie konwencji pliku nagłówkowego / źródłowego, aw praktyce jest już prawie wszechobecne.

Należy zauważyć, że pliki nagłówków mogą zostać zastąpione konwencją struktury plików projektu przez nadchodzącą funkcję modułów, którą należy rozważyć w celu włączenia do przyszłego standardu C ++ w momencie pisania (np. C ++ 20).

Podstawowy przykład

Poniższy przykład będzie zawierał blok kodu, który ma zostać podzielony na kilka plików źródłowych, co oznaczono w komentarzach do // filename .

Pliki źródłowe

// my_function.h

/* Note how this header contains only a declaration of a function.
 * Header functions usually do not define implementations for declarations
 * unless code must be further processed at compile time, as in templates.
 */

/* Also, usually header files include preprocessor guards so that every header
 * is never included twice.
 *
 * The guard is implemented by checking if a header-file unique preprocessor
 * token is defined, and only including the header if it hasn't been included
 * once before.
 */
#ifndef MY_FUNCTION_H
#define MY_FUNCTION_H

// global_value and my_function() will be
// recognized as the same constructs if this header is included by different files.
const int global_value = 42;
int my_function();

#endif // MY_FUNCTION_H

// my_function.cpp

/* Note how the corresponding source file for the header includes the interface  
 * defined in the header so that the compiler is aware of what the source file is 
 * implementing.
 *
 * In this case, the source file requires knowledge of the global constant
 * global_value only defined in my_function.h. Without inclusion of the header
 * file, this source file would not compile.
 */
#include "my_function.h" // or #include "my_function.hpp"
int my_function() {
  return global_value; // return 42;
}

Pliki nagłówkowe są następnie dołączane przez inne pliki źródłowe, które chcą korzystać z funkcjonalności zdefiniowanej przez interfejs nagłówka, ale nie wymagają wiedzy o jego implementacji (co zmniejsza łączenie kodu). Poniższy program wykorzystuje nagłówek my_function.h jak zdefiniowano powyżej:

// main.cpp

#include <iostream>       // A C++ Standard Library header.
#include "my_function.h"  // A personal header

int main(int argc, char** argv) {
  std::cout << my_function() << std::endl;
  return 0;
}

Proces kompilacji

Ponieważ pliki nagłówkowe są często częścią przepływu pracy procesu kompilacji, typowy proces kompilacji korzystający z konwencji nagłówka / pliku źródłowego zwykle wykonuje następujące czynności.

Zakładając, że plik nagłówkowy i kod źródłowy znajdują się już w tym samym katalogu, programista wykona następujące polecenia:

g++ -c my_function.cpp       # Compiles the source file my_function.cpp
                             # --> object file my_function.o

g++ main.cpp my_function.o   # Links the object file containing the 
                             # implementation of int my_function()
                             # to the compiled, object version of main.cpp
                             # and then produces the final executable a.out

Alternatywnie, jeśli chcemy najpierw skompilować plik main.cpp do pliku obiektowego, a następnie połączyć razem tylko pliki obiektowe jako ostatni krok:

g++ -c my_function.cpp
g++ -c main.cpp

g++ main.o my_function.o

Szablony w plikach nagłówka

Szablony wymagają generowania kodu w czasie kompilacji: na przykład funkcja szablonowana zostanie skutecznie przekształcona w wiele różnych funkcji, gdy funkcja szablonowana zostanie sparametryzowana przez użycie w kodzie źródłowym.

Oznacza to, że funkcja szablonu, funkcja elementu i definicje klas nie mogą być delegowane do osobnego pliku kodu źródłowego, ponieważ każdy kod, który będzie używał dowolnej konstrukcji opartej na szablonie, wymaga znajomości jego definicji w celu generowania dowolnego kodu pochodnego.

Tak więc kodowany szablon, jeśli jest umieszczony w nagłówkach, musi również zawierać swoją definicję. Przykład tego znajduje się poniżej:

// templated_function.h

template <typename T>
T* null_T_pointer() {
  T* type_point = NULL; // or, alternatively, nullptr instead of NULL
                        // for C++11 or later
  return type_point;
} 


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow