C++
Pliki nagłówkowe
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;
}