#include
на самом деле является директивой препроцессора, что означает, что они разрешаются до компиляции. Препроцессор обрабатывает каждую единицу перевода отдельно, и две единицы перевода не влияют друг на друга. Результаты этого шага не содержат никаких инструкций препроцессора (например, #include
, #ifdef
, #define
, et c).
Таким образом, после предварительной обработки оба файла, file1.cpp
и file2.cpp
, содержат содержимое header.hpp
. Затем оба компилируются в file1.o
и file2.o
. Пока проблем нет. Здесь приходит важность включить охранников. Компиляция не удастся, если блок перевода содержит дубликаты объявлений.
Представьте, что вы получили header1.hpp
:
#include "header.hpp"
class ABC { ... };
И header2.hpp
:
#include "header.hpp"
class XYZ { ... };
И какой-нибудь файл, скажем, file3.cpp
будет полагаться на оба :
#include "header1.hpp"
#include "header2.hpp"
class Foo : pulbic ABC, public XYZ {};
Без включения защиты вы заканчиваете тем, что включаете дважды header.hpp
и получаете все объявления дважды в модуле перевода, который не компилируется. (Мы только смотрим file3.cpp
здесь). С включенной защитой header.hpp
включается только один раз .
Теперь мы наконец достигли стадии связывания и вернемся к вашему первоначальному примеру. У вас есть 2 единицы компиляции, которые содержат все декалирации от header.hpp
. Компоновщик не будет заботиться о дубликатах объявлений. Компоновщик потерпит неудачу только в том случае, если он найдет несколько определений символа.
#include
s не "проверяются" или "игнорируются" на этапе компоновки, они просто не существует больше.