Защита заголовка в C++ и C
На сайте LearnCpp.com | 1.10 - Первый взгляд на препроцессор. В разделе " Защитники заголовков" есть эти фрагменты кода:
add.h:
#include "mymath.h"
int add(int x, int y);
subtract.h:
#include "mymath.h"
int subtract(int x, int y);
main.cpp:
#include "add.h"
#include "subtract.h"
При реализации защиты заголовка он упоминается следующим образом:
#ifndef ADD_H
#define ADD_H
// your declarations here
#endif
- Что может быть здесь? И, если
int main()
придет после #endif
? -
_H
ли _H
конвенцию или должен делать что-то?
Благодарю.
Ответы
Ответ 1
FILENAME_H
- это соглашение. Если вы действительно хотели, вы могли бы использовать #ifndef FLUFFY_KITTENS
как защитник заголовка (при условии, что он не определен нигде), но это было бы сложной ошибкой, если бы вы определили ее где-то в другом месте, например, количество котят для чего-то или другого.
В файле заголовка add.h объявления буквально находятся между #ifndef
и #endif
.
#ifndef ADD_H
#define ADD_H
#include "mymath.h"
int add(int x, int y);
#endif
Наконец, int main()
не должен находиться в файле заголовка. Он всегда должен находиться в файле .cpp
.
Чтобы очистить его:
#ifndef ADD_H
в основном означает "если ADD_H не был #defined
в файле или во включенном файле, затем скомпилируйте код между #ifndef
и #endif
директивами". Поэтому, если вы пытаетесь #include "add.h"
более одного раза в файле .cpp
, компилятор увидит, что ADD_H уже был #defined
, и будет игнорировать код между #ifndef
и #endif
. Защитники заголовков предотвращают включение файла заголовка несколько раз в один и тот же файл .cpp
. Защитники заголовка не препятствуют включению других файлов .cpp
из файла заголовка. Но все файлы .cpp
могут включать защищенный заголовочный файл только один раз.
Ответ 2
-
Результатом предварительной обработки одного файла реализации (.cpp) является единица перевода (TU).
-
Заголовки могут включать в себя другие заголовки, поэтому заголовок может косвенно включаться несколько раз в один и тот же TU. (Ваш пример mymath.h).
-
Определения могут возникать не более одного раза за TU. (Некоторые определения также не должны быть в нескольких TU, этот случай немного отличается и не обсуждается здесь.)
-
Проблема заключается в том, что защита защищает несколько ошибок определения, когда данный заголовок включен более одного раза в один TU.
-
Включите защитную работу путем "обертывания" содержимого заголовка таким образом, чтобы второй и последующие включения не были. Директивы # ifndef/# define должны быть первыми двумя строками файла, а #endif должен быть последним.
-
Включить охранники используются только в заголовках. Не определяйте свою основную функцию в заголовке: поместите ее в файл реализации.
Если у вас есть заголовок, который будет определять тип и объявить функцию, но также нужен сам заголовок:
#include "other_header.h"
struct Example {};
void f();
"Обертка" с включенными охранниками дает полное содержимое файла:
#ifndef UNIQUE_NAME_HERE
#define UNIQUE_NAME_HERE
#include "other_header.h"
struct Example {};
void f();
#endif
Имя, используемое для защиты включения, должно быть уникальным, иначе конфликтующие имена дадут запутанные результаты. Эти имена - это только простые макросы, и на языке, который обеспечивает определенный стиль, нет ничего. Тем не менее, соглашения по проектам обычно предъявляют требования. Существует несколько разных типов стилей, которые можно найти здесь: SO и в других местах; этот ответ дает хорошие критерии и хороший обзор.
Ответ 3
Все защитники заголовков позволяют только включить ваши заголовки один раз. (Если они включены несколько раз, они игнорируются.)
Имя, которое вы используете, не имеет значения, но обычно используется имя файла в шапке, включая расширение, как показано на рисунке.
Ваш main
должен действительно находиться в файле .cpp
, но если вы помещаете его в заголовок, поместите его в защитные устройства, чтобы он не был объявлен несколько раз.
Ответ 4
Нет, int main() идет в .cpp. Декларации - это еще один материал, который вы собираетесь добавить в заголовок. _H
- это соглашение, вы можете видеть различные соглашения защиты заголовка.
Ответ 5
Объявляю объявление в файле заголовка и определениях или int main()
входит в файл source.cpp
.
_H
нужно просто указать, что кто-то будет включать файлы заголовков, используя include guard.
Если вы используете MSVС++, вы также можете использовать #pragma once
Ответ 6
Я придумал лучшую защиту, когда есть перекрестные ссылки между двумя классами, чтобы избежать размещения предварительных объявлений вручную. Решение здесь: fooobar.com/info/67334/...