Вопрос

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

Это было полезно?

Решение

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

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

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

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

Другие советы

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

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

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

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

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

Порядок не имеет большого значения, за исключением случаев, когда вы широко используете макросы и #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>. Если я добавлю его после foo.cpp в <=>, эта отсутствующая зависимость останется незамеченной. Напротив, в порядке, который я только что представил, компилятор будет жаловаться, что <=> не был объявлен, что позволяет мне исправить <=>.

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

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

Руководство по стилю Google C++, имена и порядок включений :

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

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

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

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

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

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

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

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

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

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

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

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

Я обычно перечисляю их по мере необходимости.

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

модуль.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» не будет иметь неожиданных зависимостей.

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

модуль.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извлекаем весь файл.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top