Пользовательские заголовки выше стандартных? - PullRequest
4 голосов
/ 21 февраля 2012

Разумно ли размещать пользовательские заголовки выше в разделе include, чем стандартные заголовки?Например, включить раздел в someclass.hpp:

#include "someclass.h"
#include "global.h"

#include <iostream>
#include <string>

Это лучшая практика?Какова прибыль, если она есть?

Ответы [ 6 ]

7 голосов
/ 21 февраля 2012

Это довольно распространенная практика для #include "widget.h" как первое в widget.cpp. Это гарантирует, что widget.h является автономным, то есть не зависит непреднамеренно от других заголовочных файлов.

Кроме того, я думаю, что это вопрос личных предпочтений.

6 голосов
/ 21 февраля 2012

Причина в том, что если вы забудете включить зависимый заголовок в someclass.h, то любой файл реализации, включающий его в качестве первого заголовка, получит предупреждение / ошибку неопределенного или необъявленного типа и тому подобное. Если вы сначала включите другие заголовки, то можете скрыть этот факт - предположим, что включенные заголовки определяют требуемые типы, функции и т. Д. Пример:

my_type.h:

// Supressed include guards, etc
typedef float my_type;

someclass.h:

// Supressed include guards, etc
class SomeClass {
public:
    my_type value;
};

someclass.cpp:

#include "my_type.h" // Contains definition for my_type.
#include "someclass.h" // Will compile because my_type is defined.
...

Это будет хорошо скомпилировано. Но представьте, что вы хотите использовать SomeClass в своей программе. Если вы не включите my_type.h до включения someclass.h, вы получите сообщение об ошибке компилятора о том, что my_type не определено. Пример:

#include "someclass.h"
int main() {
    SomeClass obj;
    obj.value = 1.0;
}
3 голосов
/ 21 февраля 2012

Прежде чем углубляться в детали, необходимо сделать два важных замечания:

  1. Когда вы разрабатываете новую пару заголовок / источник, важно убедиться, что заголовок является автономным.Для этого проще всего сначала включить в файл файл.
  2. Лучше не включать посторонние вещи перед тем, как добавить заголовок, которым вы не владеете, поскольку это может создать странные проблемы в случае конфликта макросов.или перегрузка функций.

Следовательно, ответ зависит, если у вас есть модульный тест или нет.

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

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

1 голос
/ 21 февраля 2012

Хотя это всего лишь личный выбор, я бы предпочел сначала включить стандартные заголовки. Несколько причин:

  • Любой набор #ifdef..#define будет правильно отображен, а не стандартные заголовки неправильно их интерпретируют. Это касается как условной компиляции, так и значений некоторых макросов, в то время как стандартные заголовки компилируются.
  • Любое изменение / новая функция в стандартном заголовке может конфликтовать с вашей функцией, и компилятор выдаст ошибку в файле заголовка, что будет сложно решить.
  • Все требуемые стандартные заголовки должны быть помещены в один заголовок (предпочтительно некоторый предварительно скомпилированный заголовок), включать этот заголовок и затем включать ваш пользовательский заголовок. Это уменьшит время компиляции.
1 голос
/ 21 февраля 2012

Начните с системных заголовков.

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

Я основываю этот один из моих самых первых курсов программирования (я думаю, в 1984 году), где мы программировали на Лиспе, и нас учили думать какэто: вы начинаете с обычного языка Lisp, а затем создаете новый язык, более полезный для вашего приложения, добавляя некоторые функции и типы данных.Если вы, например, добавили даты и возможность манипулировать датами, этот новый язык можно назвать Lisp-with-date.Затем вы можете использовать Lisp-with-date для создания нового языка с функциональностью календаря, который можно назвать Lisp-with-calendars.Как слои в луке.

Аналогично, вы можете рассматривать C как имеющий «основной» язык без заголовков, а затем, например, вы можете расширить этот язык на новый, более широкий язык с функциональными возможностями ввода / вывода.по #include stdio.h.Вы добавляете все больше и больше материала в основной язык, включая больше заголовков.(Я знаю, что термин «язык C» в других контекстах относится ко всему стандарту со всеми стандартными заголовками, но имейте в виду, что здесь.) Каждый новый заголовок #included создает новый, более широкий язык и дополнительный слойлук.

Теперь мне кажется, что стандартные заголовки, очевидно, должны быть внутренней частью этого лука и, следовательно, перед пользовательскими заголовками.Вы можете создать язык C-with-monsters, добавив материал в C-with-I / O, но люди, создавшие C-with-I / O, не начали с C-with-monsters.

0 голосов
/ 21 февраля 2012

любое место, куда вы включаете компилятор c ++, рассматривает его как то же самое

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...