Подтвердить что ты не робот

Порядок заголовка С++

Какой порядок заголовков должен быть объявлен в файле заголовка /cpp? Очевидно, что те, которые требуются для последующих заголовков, должны быть более ранними, а заголовки классов должны быть в области видимости cpp, а не в области заголовка, но существует ли установленное соглашение/наилучшая практика?

4b9b3361

Ответ 1

В файле заголовка вы должны включить ВСЕ заголовки, чтобы сделать его компилируемым. И не забудьте использовать форвардные объявления вместо некоторых заголовков.

В исходном файле:

  • соответствует заголовочному файлу
  • необходимые заголовки проекта
  • Заголовки сторонних библиотек
  • заголовки стандартных библиотек
  • системные заголовки

В этом порядке вы не пропустите ни один из ваших файлов заголовков, который забыл включать библиотеки самостоятельно.

Ответ 2

Хорошая практика: каждый файл .h должен иметь .cpp, который включает в себя этот .h сначала перед чем-либо еще. Это доказывает, что любой файл .h можно поместить первым.

Даже если заголовок не требует реализации, вы создаете .cpp, который включает только этот файл .h и ничего больше.

Это означает, что вы можете ответить на свой вопрос любым способом. Неважно, в какой порядок вы их включаете.

Для дальнейших замечательных советов попробуйте эту книгу: крупномасштабный дизайн программного обеспечения на C++ - это позор, это так дорого, но это практически руководство по выживанию для компоновки исходного кода на С++.

Ответ 3

В заголовочных файлах я сначала помещаю стандартные заголовки, а затем свои собственные заголовки (оба списка упорядочены по алфавиту). В файлах реализации я помещаю сначала соответствующий заголовок (если есть), то заголовки стандартов и другие заголовки зависимостей.

Заказ имеет мало значения, за исключением случаев, когда вы отлично используете макросы и #define; в этом случае вы должны проверить, что макрос, который вы определили, не заменяет ранее включенный (за исключением того, что вы хотите, конечно).

Относительно этого утверждения

те, которые требуются для последующих заголовков, должны быть более ранними

Заголовок не должен полагаться на другие заголовки, которые были включены до него! Если он требует заголовков, он просто включает их. Защитники заголовков предотвратят множественное включение:

#ifndef FOO_HEADER_H
#define FOO_HEADER_H
...
#endif

ИЗМЕНИТЬ

Поскольку я написал этот ответ, я изменил способ упорядочения директив include в своем коде. Теперь я стараюсь всегда ставить заголовки в возрастающем порядке стандартизации, поэтому сначала появляются заголовки моего проекта, а затем заголовки сторонних библиотек, за которыми следуют стандартные заголовки.

Например, если один из моих файлов использует библиотеку, которую я написал, Qt, Boost и стандартную библиотеку, я закажу их следующим образом:

//foo.cpp
#include "foo.hpp"

#include <my_library.hpp>
// other headers related to my_library

#include <QtCore/qalgorithms.h>
// other Qt headers

#include <boost/format.hpp> // Boost is arguably more standard than Qt
// other boost headers

#include <algorithms>
// other standard algorithms

Причина, по которой я делаю это, - обнаружить недостающие зависимости в моих собственных заголовках: допустим, например, что my_library.hpp использует std::copy, но не включает <algorithm>. Если я включу его после <algorithm> в foo.cpp, эта отсутствующая зависимость останется незамеченной. Напротив, в том порядке, который я только что представил, компилятор будет жаловаться, что std::copy не был объявлен, что позволяет мне исправить my_library.hpp.

В каждой группе "library" я стараюсь, чтобы директивы include упорядочивались по алфавиту, чтобы найти их более легко.

В боковом поле хорошей практикой также является максимальное ограничение зависимости между заголовочными файлами. Файлы должны содержать как можно меньше заголовков, особенно файл заголовков. Действительно, чем больше заголовков вы включаете, тем больше кода нужно перекомпилировать, когда что-то изменится. Хорошим способом ограничения этих зависимостей является использование форвардного объявления, что очень часто бывает в файлах заголовков (см. Когда я могу использовать декларацию forward?).

Ответ 4

Руководство, названия и порядок использования Google С++:

В каталоге dir/foo.cc, основная цель которого - реализовать или протестировать материал в каталоге dir2/foo2.h, выполните следующие действия:

  • dir2/foo2.h(предпочтительное местоположение - см. подробности ниже).
  • Системные файлы C.
  • Системные файлы С++.
  • Файлы других библиотек.
  • Ваши файлы проекта .h.

Ответ 5

Я заказывал их в алфавитном порядке (легче найти)

Ответ 6

"Как" не очевидно, но "что". Ваша цель - убедиться, что порядок, в который вы включаете файлы заголовков, никогда не имеет значения (и я имею в виду "НИКОГДА!" ).

Хорошей помощью является проверка того, собираются ли файлы заголовков при создании файлов cpp (по одному для каждого заголовочного файла), которые включают только один из них.

Ответ 7

Для файлов .cpp вы должны включить заголовок класса или то, что вы реализуете первым, так что вы поймаете случай, когда этот заголовок отсутствует. После этого большинство руководств по кодированию, как правило, включают заголовки систем, во-первых, заголовки проектов, например Руководство по стилю Google С++.

Ответ 8

Это зависимость, и это во многом зависит от того, что вы вкладываете в наши заголовки. Факт в том, что вы можете быть действительно известными в этом и сводить к минимуму, чтобы ваши требования были строгими, но в конечном итоге вы столкнетесь с сценарием, в котором вы захотите использовать защитники включения.

#ifndef MY_HEADER_H
#define MY_HEADER_H
//...
#endif

Проблема не так очевидна в начале, но по мере того, как сложность вашего программного обеспечения растет, так и ваши зависимости. Вы можете преуспеть и быть в курсе, но более крупные проекты на С++, как правило, пронизаны включенными. Вы можете попробовать, но вы можете сделать так много. Поэтому будьте старательны и подумайте о своих предложениях, ДА! Но в какой-то момент у вас наверняка будут циклические зависимости, и именно поэтому вам нужны охранники включения.

Ответ 9

Если заголовку нужны другие заголовки, он просто включает их в этот заголовок.

Попробуйте структурировать свой код, чтобы передать указатели или ссылки и переслать объявление, где вы можете.

В реализации затем заголовок, который его определяет, должен быть указан первым (кроме Visual Studio, если вы используете pch, тогда stdafx будет первым).

Я обычно перечисляю их как мне нужно.

Ответ 10

Я нашел следующее соглашение наиболее полезным:

module.cpp:

// this is the header used to trigger inclusion of precompiled headers
#include <precompiled.h> 
// this ensures that anything that includes "module.h" works
#include "module.h"
// other headers, usually system headers, the project

Важно, чтобы заголовок модуля был первым, а не прекомпилированным заголовком. Это гарантирует, что "module.h" не имеет неожиданных зависимостей.

Если вы работаете над большим проектом с медленным временем доступа к диску, я видел этот стиль, используемый для уменьшения времени сборки:

module.cpp:

// this is the header used to trigger inclusion of precompiled headers
#include <precompiled.h> 
// this ensures that anything that includes "module.h" works
#include "module.h"
// other headers, usually system headers, the project
#if !defined _OTHER_MODULE_GUARD_
#include "other_module.h"
#endif 

#if !defined _ANOTHER_MODULE_GUARD_
#include "another_module.h"
#endif 

Это немного подробный, но он сохраняет на диске поиск, так как заголовок не будет искать/открыть, если он уже включен. Без проверки безопасности компилятор будет искать и открывать файл заголовка, проанализировать весь файл, чтобы #ifdef удалить весь файл.