Если ваш ответ - «файл cpp должен
#include
каждый заголовок, который ему нужен», доведенный до логического завершения, это будет означать, что почти каждый файл cpp должен#include
и т. Д., Поскольку большая часть кода в конечном итоге будет их использовать, и если вы не должны полагаться на какой-либо другой заголовок, включающий их, ваш cpp должен включить их явно.,
Ага. Я предпочитаю именно так.
Если «шум» слишком велик, можно иметь «глобальный» включаемый файл, содержащий обычный общий набор включаемых (например, stdafx.h
] во многих программах Windows) и включать его в начало каждого файла .cpp
(что также помогает с предварительно скомпилированными заголовками).
Я думаю, вам все равно следует включить оба файла. Это помогает поддерживать код.
// Foo.cpp
#include <Library1>
#include <Library2>
Я могу прочитать это и легко увидеть, какие библиотеки он использует. Если Library2
использовал Library1
, и он был преобразован в это:
// Foo.cpp
#include <Library2>
Но я все еще видел код Library1
, я мог бы быть немного сбит с толку. Нетрудно догадаться, что какая-то другая библиотека должна включать его, но это все еще мыслительный процесс, который должен происходить.
Явность означает, что мне не нужно гадать, даже для дополнительной микросекунды компиляции.
Я думаю, вы должны включать оба, пока это не станет невыносимым. Затем выполните рефакторинг ваших классов и исходных файлов, чтобы уменьшить взаимосвязь, на том основании, что если просто перечислить все ваши зависимости обременительно, то, вероятно, у вас слишком много зависимостей ...
Компромиссом может быть утверждение, что если что-то в bar.h
содержит определение класса (или объявление функции), для которого обязательно требуется определение другого класса из qux.h
, тогда bar.h
может предполагаться / должен включать qux.h
, а пользователь API в bar.h
не нужно беспокоиться о включении обоих.
Итак, предположим, что клиент хочет думать о себе как о "действительно" интересующемся только API панели, но должен использовать qux тоже, потому что он вызывает функцию bar, которая принимает или возвращает объект qux по значению. Тогда можно просто забыть, что у qux есть собственный заголовок, и представить себе, что это одна большая панель API, определенная в bar.h
, причем qux просто является частью этого API.
Это означает, что вы не можете рассчитывать, например, на поиск в файлах cpp упоминаний о qux.h
, чтобы найти всех клиентов qux. Но я бы никогда не стал на это полагаться, поскольку в целом слишком легко случайно пропустить явно включенную зависимость, которая уже косвенно включена, и никогда не понять, что вы не перечислили все соответствующие заголовки. Так что вам, вероятно, ни в коем случае не следует предполагать, что списки заголовков завершены, а вместо этого используйте doxygen (или gcc -M, или что-то еще), чтобы получить полный список зависимостей и выполнить поиск в нем.
как насчет того, если foo.cpp включает bar.h и qux.h, но оказывается, что bar.h сам включает qux. час? Должен ли foo.cpp избегать включения qux.h?
Если foo.cpp
напрямую использует что-либо из qux.h
, то он должен включать сам этот заголовок. В противном случае, поскольку bar.h
требует qux.h
, я бы полагался на bar.h
, включая все, что ему нужно.
Каждый файл заголовка содержит определения, необходимые для использования службы определенного типа (определение класса, некоторые макросы и т. Д.). Если вы напрямую используете службы, представленные через файл заголовка, включите этот файл заголовка, даже если другой файл заголовка также включает его. С другой стороны, если вы используете эти службы только косвенно, только в контексте служб другого файла заголовка, не включайте файл заголовка напрямую.
На мой взгляд, в любом случае это не имеет большого значения. Второе включение файла заголовка не анализируется полностью; он в основном закомментирован для всех, кроме первого раза. По мере того, как все меняется и вы обнаруживаете, что использовали файл заголовка, который не включали напрямую, добавить его не составит труда.
Один из способов понять, использует ли foo.cpp напрямую qux.h, - это подумать о том, что произойдет, если foo.cpp больше не будет включать bar.h. Если в foo.cpp по-прежнему необходимо включать qux.h, его следует указать явно. Если ему больше не потребуется ничего из qux.h, вероятно, нет необходимости включать его явно.
См. SmartDifferencer для получения информации об инструменте, который понимает синтаксис языка и абстрактные команды редактирования, такие как «перемещение этот блок кода от строки A до строки B "," переименуйте эту переменную везде в области видимости ". В настоящее время доступно для Java и COBOL, а также для других языков после Real Soon.
РЕДАКТИРОВАТЬ 04.09.2009: добавлен C # ...
РЕДАКТИРОВАТЬ 5/2011: Добавлено много языков: C ++, JavaScript, другие ... Проверить сайт .
Наш опыт показывает, что активный поиск заголовков, которые полностью не используются (или могли бы быть, с правильными предварительными декларациями), и их удаление гораздо более достойно времени и усилий, чем выяснение цепочек включения для возможные дубликаты. И хороший lint (splint, PC-Lint и т. Д.) Может помочь вам в этом определении.
Еще более достойным нашего времени и усилий было выяснить, как заставить наш компилятор обрабатывать несколько единиц компиляции на выполнение (почти линейное ускорение для нас, до определенного момента - компиляция полностью зависела от запуска компилятора).
После этого вы, возможно, захотите рассмотреть безумие "одного большого CPP". Это может быть очень впечатляюще.
с правильными форвардными объявлениями), и их удаление стоит гораздо больше времени и усилий, чем выяснение цепочек включения для возможных дубликатов. И хороший lint (splint, PC-Lint и т. Д.) Может помочь вам с этим определением.Еще более достойным нашего времени и усилий было выяснить, как заставить наш компилятор обрабатывать несколько единиц компиляции на выполнение (почти линейное ускорение для нас, до определенного момента - компиляция полностью зависела от запуска компилятора).
После этого вы, возможно, захотите рассмотреть безумие "одного большого CPP". Это может быть очень впечатляюще.
с правильными форвардными объявлениями), и их удаление стоит гораздо больше времени и усилий, чем выяснение цепочек включения для возможных дубликатов. И хороший lint (splint, PC-Lint и т. Д.) Может помочь вам с этим определением.Еще более достойным нашего времени и усилий было выяснить, как заставить наш компилятор обрабатывать несколько единиц компиляции на выполнение (почти линейное ускорение для нас, до определенного момента - компиляция полностью зависела от запуска компилятора).
После этого вы, возможно, захотите рассмотреть безумие "одного большого CPP". Это может быть очень впечатляюще.
Еще более достойным нашего времени и усилий было выяснить, как заставить наш компилятор обрабатывать несколько единиц компиляции за одно выполнение (почти линейное ускорение для нас, до определенного момента - компиляция полностью зависела от запуска компилятора).
После этого вы можете подумать о безумии "одного большого CPP". Это может быть очень впечатляюще.
Еще более достойным нашего времени и усилий было выяснить, как заставить наш компилятор обрабатывать несколько единиц компиляции за одно выполнение (почти линейное ускорение для нас, до определенного момента - компиляция полностью зависела от запуска компилятора).
После этого вы можете подумать о безумии "одного большого CPP". Это может быть очень впечатляюще.