где следует включить include в C ++ - PullRequest
28 голосов
/ 19 февраля 2010

Я читаю некоторый код на С ++ и обратите внимание, что в файлах заголовков и файлах .cpp есть "#include". Я предполагаю, что если я переместлю все «#include» в файле, скажем, foo.cpp, тоже его 'заголовочный файл foo.hh, и пусть foo.cpp включает только foo.hh, код должен работать в любом случае без учета таких проблем недостатки, эффективность и пр.

Я знаю, что моя идея "внезапно" должна быть в некотором роде плохой идеей, но каковы ее точные недостатки? Я новичок в c ++, поэтому я не хочу читать много книг по C ++, прежде чем смогу ответить на этот вопрос самостоятельно. так что просто оставьте вопрос здесь для вашей помощи. заранее спасибо.

Ответы [ 9 ]

32 голосов
/ 19 февраля 2010

Как правило, включайте свои включения в файлы .cpp, когда это возможно, и только в файлы .h, когда это невозможно.

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

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

13 голосов
/ 19 февраля 2010

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

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

Включение загрязнения файлов - это, на мой взгляд, одна из худших форм разложения кода.1006 * править: Хех.Похоже, парсер съедает символы> и <. </p>

5 голосов
/ 19 февраля 2010

Вы бы заставили все остальные файлы, включая ваш заголовочный файл, транзитивно включать все #include s в ваш заголовок.

В C ++ (как в C) #include обрабатывается препроцессором, просто вставляявесь текст в файле #include d вместо оператора #include.Таким образом, с большим количеством #include s вы можете буквально похвастаться размером вашего компилируемого файла до сотен килобайт - и компилятору необходимо проанализировать все это для каждого отдельного файла.Обратите внимание, что один и тот же файл, содержащийся в разных местах, должен быть повторно обработан в каждом отдельном месте, где он равен #include d!Это может замедлить компиляцию до сканирования.

Если вам нужно объявить (но не определить) вещи в вашем заголовке, используйте прямое объявление вместо #include s.

1 голос
/ 19 февраля 2010

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

1 голос
/ 19 февраля 2010

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

Стандартный пример #include <vector>. Получает вам векторный класс. И множество внутренних файлов заголовков CRT, которые необходимы для правильной компиляции векторного класса, вещи, которые вам действительно не нужны или о которых вы не хотите знать.

1 голос
/ 19 февраля 2010

.hh (или .h) файлы должны быть для объявлений.

.cpp (или .cc) файлы должны быть для определений и реализаций.

Сначала поймите, чтооператор #include литерал .#include "foo.h" буквально копирует содержимое файла foo.h и вставляет его туда, где директива include находится в другом файле.

Идея состоит в том, что некоторые другие файлы bar.cpp и baz.cpp могут захотеть использоватьнекоторый код, который существует в foo.cc.Обычно это можно сделать для bar.cpp и baz.cpp до #include "foo.h", чтобы получить объявления функций или классов, которые они хотят использовать, и затем во время компоновки компоновщик подключит эти варианты использования.в bar.cpp и baz.cpp к реализациям в foo.cpp (в этом весь смысл компоновщика).

Если вы поместите все в foo.h и попытаетесь это сделать, у вас возникнет проблема,Скажем, что foo.h объявляет функцию с именем doFoo().Если определение (код для) этой функции находится в foo.cc, это нормально.Но если код для doFoo() перемещен в foo.h, а затем вы включили foo.h в foo.cpp, bar.cpp и baz.cpp, теперь есть три определения для функции с именем doFoo(), и вашкомпоновщик будет жаловаться, потому что вам не разрешено иметь более одной вещи с одним и тем же именем в одной и той же области видимости.

1 голос
/ 19 февраля 2010

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

1 голос
/ 19 февраля 2010

Если вы #include .cpp файлы, вы, вероятно, в конечном итоге с множеством ошибок "множественного определения" от компоновщика.Теоретически вы можете #include все в одну единицу перевода, но это также означает, что все должно быть пересоздано каждый раз, когда вы вносите изменения в один файл.Для реальных проектов это недопустимо, поэтому у нас есть линкеры и инструменты, такие как make.

0 голосов
/ 19 февраля 2010

Вы можете избежать множественных ошибок определения, если используете «включить охрану».

(begin myheader.h)
#ifndef _myheader_h_
#define _myheader_h_
struct blah {};
extern int whatsit;
#endif //_myheader_h_

Теперь, если вы #include «myheader.h» в других заголовочных файлах, он будет включен только один раз (из-зачтобы _myheader_h_ был определен).Я считаю, что у MSVC есть «#pragma Once» с эквивалентной функциональностью.

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