2013-05-16 3 views
3

Мне было интересно, есть ли какие-либо pro и contra, содержащие инструкции непосредственно в файлах include, а не в их исходном файле.Лучшая практика для включения из файлов include

Лично мне нравится включать в себя «чистый», поэтому, когда я включаю их в некоторый файл c/cpp, мне не нужно выслеживать каждый возможный заголовок, потому что включенный файл сам по себе не заботится , С другой стороны, если у меня есть включенные в include файлы, время компиляции может увеличиться, потому что даже с включенными защитами файлы сначала должны быть проанализированы. Это просто вопрос вкуса, или есть какие-то плюсы и минусы над другим?

Что я имею в виду:

sample.h

#ifdef ... 

#include "my_needed_file.h" 
#include ... 

class myclass 
{ 
} 

#endif 

sample.c

#include "sample.h" 

my code goes here 

Versus:

sample.h

#ifdef ... 

class myclass 
{ 
} 

#endif 

sample.c

#include "my_needed_file.h" 
#include ... 
#include "sample.h" 

my code goes here 
+2

Удачи, скомпилировав класс в C. – cHao

+0

Каждый из них увеличивает время компиляции и перетаскивает больше идентификаторов. Вы хотите ограничить оба. Если вам не нужно включать в sample.h, чтобы он работал с other_translation_unit.cpp, не добавляйте его в sample.h. И если вы считаете, что время перевода не имеет большого значения, вы еще не пробовали шаблонные заголовки C++.;-) – DevSolar

+0

Вы включаете те же заголовки в обоих примерах, как бы время сборки увеличивалось? –

ответ

7

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

Если файл реализации нуждается в том, что явно не требуется в заголовке, то этот файл реализации должен включать его сам.

+1

На стороне: вы должны включить все, что вам нужно в заголовке. Я действительно ненавижу, когда вопрос о включении заголовков имеет значение;) –

+1

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

+0

Конечно. Один из самых забавных примеров, о которых я думал, - это кто-то, объявляющий ':: std :: ostream & operator << (:: std :: ostream &, T);' для кучи типов в нашей базе кода ... и никогда не включая '' в заголовках, где он это сделал. Нет проблем для него, так как он * всегда * включал 'iostream' перед любыми другими заголовками ... –

2

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

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

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

+0

Ну, из ocurse я включаю только заголовочный файл, что необходимо для этого конкретного заголовка. Однако, когда мне нужно, например, строки, и я включаю '#include 'очень вероятно, что другие заголовки делают то же самое. Но, с другой стороны, если я их не включаю, то SOMEBODY должен включать их, тем самым вынуждая пользователя искать то, что нужно самому, вместо того, чтобы иметь его как последовательный API. – Devolus

1

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

1

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

Если ваш компилятор не помнит, какие файлы включают в себя защитные меры и избегать повторного открытия и повторного токенизации файла, тогда получите лучший компилятор. Большинство современных компиляторов делали это в течение многих лет, поэтому нет никаких затрат на включение одного и того же файла несколько раз (при условии, что у него есть защита). См.http://gcc.gnu.org/onlinedocs/cpp/Once_002dOnly-Headers.html

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

Если my_needed_file.h необходимо перед темsample.h (потому что sample.h требует деклараций/определения из него), то она должна быть включена в sample.h, не вопрос. Если это не нужны sample.h и нужно только в sample.c только тогда включить его там, и я предпочитаю, чтобы включить его послеsample.h, таким образом, если sample.hявляется отсутствует все заголовки, которые необходимы, то вы будете знать об этом раньше:

// sample.c 
#include "sample.h" 
#include "my_needed_file.h" 
#include ... 
#include <std_header> 
// ... 

Если вы используете этот #include порядок, то это заставляет вас сделать sample.h самодостаточным, который гарантирует, что вы не вызывают проблем и раздражающие для других пользователей заголовка.

3

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

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

-1

Я думаю, что второй подход является лучшим только по причине.

  1. , когда у вас есть шаблон функции в файле заголовка.

    class myclass 
    { 
        template<class T> 
        void method(T& a) 
        { 
         ... 
        } 
    } 
    

И вы не хотите использовать его в исходном файле myclass.cxx. Но вы хотите использовать его в xyz.cxx, если вы займетесь своим первым подходом, тогда вы в конечном итоге включите все файлы, необходимые для myclass.cxx, что бесполезно для xyz.cxx.

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

Смежные вопросы