где должен “включать” быть помещенным в C++

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

  • Восстановите свои модули, чтобы не было перекрестных импортов, т.е. одиночный модуль и т. д.
  • Заменить from module import foo на import module и использовать полные имена.
  • Поместить импорт в конец модулей (не рекомендуется).

См. также Циркулярный импорт в Python .

29
задан Chris Dwyer 19 February 2010 в 06:16
поделиться

9 ответов

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

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

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

33
ответ дан jkp 20 November 2019 в 00:40
поделиться

.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
ответ дан Tyler McHenry 20 November 2019 в 00:40
поделиться

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

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

1
ответ дан Hans Passant 20 November 2019 в 00:40
поделиться

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

(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» с эквивалентной функциональностью.

0
ответ дан Arthur Kalliokoski 20 November 2019 в 00:40
поделиться

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

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

Загрязнение включаемых файлов, на мой взгляд, одна из худших форм гниения кода.

править: Хех. Похоже, парсер съедает символы> и <.

14
ответ дан 28 November 2019 в 01:22
поделиться

До сих пор много хороших ответов. Вот просвет:

$ make 2>&1 | tee filetokeepitin.txt 

позволит вам наблюдать за прокручиванием выходных данных.

-121--1004010-

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

-121--1577317-

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

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

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

6
ответ дан 28 November 2019 в 01:22
поделиться

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

1
ответ дан 28 November 2019 в 01:22
поделиться

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

2
ответ дан 28 November 2019 в 01:22
поделиться

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

1
ответ дан 28 November 2019 в 01:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: