C++
Файлы заголовков
Поиск…
замечания
В C ++, как и в C, компилятор C ++ и процесс компиляции используют препроцессор C. Как указано в руководстве для препроцессора GNU C, заголовочный файл определяется следующим образом:
Заголовочный файл представляет собой файл, содержащий объявления C и определения макросов (см. Макросы) для совместного использования нескольких исходных файлов. Вы запрашиваете использование файла заголовка в своей программе, включив его, с директивой предварительной обработки C «#include».
Файлы заголовков служат для двух целей.
- Файлы заголовков системы объявляют интерфейсы к частям операционной системы. Вы включаете их в свою программу для предоставления определений и деклараций, необходимых для вызова системных вызовов и библиотек.
- Ваши собственные заголовочные файлы содержат декларации для интерфейсов между исходными файлами вашей программы. Каждый раз, когда у вас есть группа связанных деклараций и макроопределений, все или большинство из которых необходимы в нескольких разных исходных файлах, рекомендуется создать для них заголовочный файл.
Однако для самого препроцессора C заголовочный файл не отличается от исходного файла.
Схема организации заголовка / исходного файла представляет собой просто строгое и стандартное соглашение, устанавливаемое различными проектами программного обеспечения, чтобы обеспечить разделение между интерфейсом и реализацией.
Несмотря на то, что сам стандарт C ++ официально не применяется, рекомендуется использовать правило заголовка / исходного файла, и на практике оно уже почти повсеместно.
Обратите внимание, что заголовочные файлы могут быть заменены как соглашение о структуре файла проекта с помощью предстоящей функции модулей, которая по-прежнему должна рассматриваться для включения в будущий стандарт C ++ на момент написания (например, C ++ 20).
Основной пример
Следующий пример будет содержать блок кода, который должен быть разделен на несколько исходных файлов, как обозначается // filename
.
Исходные файлы
// 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;
}
Заголовочные файлы затем включаются в другие исходные файлы, которые хотят использовать функциональные возможности, определенные интерфейсом заголовка, но не требуют знания его реализации (таким образом, уменьшая связь кода). Следующая программа использует заголовок my_function.h
как указано выше:
// 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;
}
Процесс компиляции
Поскольку файлы заголовков часто являются частью процесса обработки процесса компиляции, типичный процесс компиляции, использующий соглашение заголовка / исходного файла, обычно выполняет следующее.
Предполагая, что файл заголовка и файл исходного кода уже находятся в одном каталоге, программист выполнит следующие команды:
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
В качестве альтернативы, если вы хотите сначала скомпилировать main.cpp
в объектный файл, а затем связать только файлы объектов вместе в качестве последнего шага:
g++ -c my_function.cpp
g++ -c main.cpp
g++ main.o my_function.o
Шаблоны в файлах заголовков
Шаблонам требуется генерация кода во время компиляции: например, шаблонная функция будет эффективно превращена в несколько различных функций, как только параметризованная функция будет параметризоваться, используя исходный код.
Это означает, что функция шаблона, функция-член и определения классов не могут быть делегированы в отдельный файл исходного кода, так как любой код, который будет использовать любую шаблонную конструкцию, требует знания своего определения, как правило, генерирующего любой производный код.
Таким образом, шаблонный код, если он помещен в заголовки, также должен содержать его определение. Ниже приведен пример:
// 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;
}