Когда вы строите свой проект, каждый файл .cpp компилируется отдельно в разные объектные файлы.once
в #pragma once
применяется только к компиляции одного файла .cpp, но не для проекта в целом.Таким образом, если файл .cpp содержит заголовок A и заголовок B, а заголовок B также включает заголовок A, то второе включение заголовка A будет пропущено.
Однако, если у вас есть другой файл .cpp, который включает в себя A, A будет снова включен в этот объектный файл - потому что #pragma once
работает только при компиляции одного файла .cpp.
Инструкция #include буквально берет содержимое включенного файла и «вставляет» его в файл, который его включил.Вы можете попробовать это, посмотрев на вывод инструмента препроцессора C (cpp
в наборе инструментов gcc
).Если вы используете цепочку инструментов gcc, вы можете попробовать что-то вроде этого, чтобы увидеть файл после применения его включений:
cpp file.cpp -o file_with_includes.cpp
Если у вас есть функция в заголовке, например, Assert
в вашем примере, функция реплицируется в каждый файл .cpp, в который вы ее включаете.
Если у вас есть A.cpp и B.cpp, которые оба содержат ваш файл Constants.h, каждый объектный файл (.o или .obj)в зависимости от вашей среды) будет включать копию вашей функции Assert.Когда компоновщик объединяет объектные файлы для создания двоичного файла, оба объектных файла объявляют, что они предоставляют определение для Assert, и компоновщик будет жаловаться, потому что он не знает, какой из них использовать.
Решениездесь можно либо встроить функцию Assert, например:
inline void Assert(bool val, string s)
{
if (!val)
{
cout << "Assertion Failed!!: " << s << endl;
exit(-1);
}
}
, либо предоставить ее тело в своем собственном файле .cpp, оставив в заголовке только прототип функции.
Константы.h:
void Assert(bool val, string s);
Constants.cpp:
void Assert(bool val, string s)
{
if (!val)
{
cout << "Assertion Failed!!: " << s << endl;
exit(-1);
}
}
Обратите внимание, стандартная библиотека также предлагает assert()
, что тоже хорошо работает.(см. https://en.cppreference.com/w/cpp/error/assert).
#include <cassert>
...
assert(is_my_condition_true());
assert(my_variable > 23);
// etc..
Просто имейте в виду, что assert, объявленный в cassert
, работает только при компиляции для Debug и компилируется при сборке для Release (для ускорения выполнения), так чтоне ставьте код в assert, который имеет побочные эффекты.
#include <cassert>
...
// Don't call functions with side effects.
// Thus function decreases a "count" and returns the new value
// In Release builds, this line will disappear and the decrement
// won't occur.
assert(myclass.decrement_count() > 0);