Заголовочные файлы, include и ODR
Зачем нужны заголовки
Заголовочный файл (.h или .hpp) обычно содержит объявления, которые нужны другим частям программы. Файл .cpp содержит определения функций и реализацию.
// Math.h#pragma onceint Add(int a, int b);// Math.cpp#include "Math.h"int Add(int a, int b) { return a + b;}Другой .cpp подключает Math.h и вызывает Add. Каждый .cpp компилируется отдельно, а затем объектные файлы связываются линкером.
Защита от повторного включения
#pragma once поддерживается распространёнными компиляторами. Альтернатива — include guards:
#ifndef MATH_H#define MATH_Hint Add(int a, int b);#endifОшибки линковки
Если функция объявлена, но нигде не определена, часто возникает ошибка undefined reference или unresolved external. Если обычное определение функции помещено в заголовок и включается в несколько .cpp, возможны множественные определения.
Для функции, определение которой находится в заголовке и включается в разные единицы трансляции, применяют inline при соблюдении правил ODR. inline не означает, что компилятор обязан встроить вызов.
Что помещать в заголовок
- объявления типов и функций;
- объявления классов и их членов;
- шаблоны, которым требуется видимость определения;
- короткие функции, определённые как
inline.
Не включай лишние заголовки. По возможности используй предварительные объявления, если они безопасны и уменьшают зависимости.
Итог
Заголовок задаёт интерфейс, .cpp обычно содержит реализацию. Понимание единиц трансляции, include guards и ODR помогает быстро разбираться в ошибках линковки.
