2015-07-10 3 views
0

Например, я хочу два файла заголовка, которые могут зависеть от функции от другого файла заголовка.Почему заголовочный файл Head1.h не содержит заголовочный файл Head2.h, который включает Head1.h?

//Header1.h file 
#include Header2.h 
void h1(){ 
    //... 
    func1(); 
} 
void h2(); 

//Header2.h file 
#include Header1.h 
void func1(); 
void func2(){ 
    //some other code... 
    h2(); 
} 

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

#ifndef HEADER1_H 
#define HEADER1_H 
//Header1.h... 
#endif 

Почему это не разрешено? Или, есть ли способ скомпилировать это, чтобы он работал?

+2

См [вперед декларации] (HTTP: // StackOverflow.com/questions/4757565/c-forward-declaration) – Miki

+0

Не ставьте определения в заголовки. –

ответ

4

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

Во-вторых, использование #ifndef включает в себя защитные устройства в файле заголовка, в какой-то момент просто прерывает бесконечный цикл. То есть круговое включение превратится в последовательный включение с одним файлом, включенным первым, а второй - вторым. Но последовательное включение (в любом порядке) не поможет разрешить какие-либо циклические зависимостей объявления, присутствующих в ваших файлах заголовков.

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

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

1

Вы создаете круговую зависимость, когда включаете Header1.h в Header2.h и наоборот. Вы можете решить эту проблему одним из двух способов:

1) Переместите определение каждой функции в .cpp файле:

//Header1.h file 
void h1(); 
void h2(); 

//Header2.h file 
void func1(); 
void func2(); 

//my1.cpp file 
#include Header1.h 
#include Header2.h 
void h1(){ 
    //... 
    func1(); 
} 
void h2() { 
} 

//my2.cpp file 
#include Header1.h 
#include Header2.h 
void func1() { 
} 
void func2(){ 
    //some other code... 
    h2(); 
} 

2) По предложению @Miki проверки What are forward declarations in C++?

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

  • Нет связанных вопросов^_^