Ren
Ren

Reputation: 463

Why can't a header file Head1.h include a header file Head2.h that includes Head1.h?

For example, I want two header files which can depend on a function from the other header file.

//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();
}

This may not seem that big of an issue, but in order for some files to be logically coherent, I sometimes want this kind of dependency. I've ran into this issue multiple times in Visual Studio, while compiling C++ code. But this never compiles even when I include the respective header guards for each file, i.e.

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

Why isn't this allowed? Or, is there some way to compile this so it will work?

Upvotes: 0

Views: 158

Answers (2)

AnT stands with Russia
AnT stands with Russia

Reputation: 320421

Firstly, #include is a preprocessor directive that performs full textual substitution of one text file into another text file. Two header files trying to #include each other form an infinite loop of nested textual substitutions. I think it should be obvious that an infinite loop of textual substitutions will not "work", simply because it is infinite.

Secondly, using #ifndef include guards in the header file will simply break the infinite loop at some point. I.e. the circular inclusion will turn into sequential inclusion with one file included first and another file included second. But sequential inclusion (in any order) will not help to resolve any circular declaration dependencies present in your header files.

For this reason circular inclusion of header files never makes any sense (aside form very special contexts, like preprocessor tricks), regardless of whether you use include guards or not. Circular inclusion never achieves anything. You have to design your header files so that they don't even attempt to rely on circular inclusion. I.e. you have to stratify your declarations and your header files into lower-level and higher-level ones, and always include lower into higher (but not the other way around), and resolve any circular declaration dependencies by using forward-declarations in lower-level headers.

Sometimes header files call for circular inclusion simply because they are poorly designed. For example, even when there are no circular dependencies between the declarations, these declarations might be incorrectly distributed between header files, leading to a perceived need to include headers into each other circularly. In such cases it is always a better idea to refactor your headers in order to eliminate any circular declaration dependencies. E.g. redistribute declarations between the headers, extract portions of two mutually dependent headers into a third lower-level header etc. And only when such refactoring is not possible, i.e. you have a genuine circular declaration dependency, use forward-declarations as a last resort.

Upvotes: 4

Mital Vora
Mital Vora

Reputation: 2249

You are creating circular dependency when you include Header1.h in Header2.h and vice versa. You can solve it in one of two ways:

1) Move the definition of every function in .cpp file:

//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) As suggested by @Miki checkout What are forward declarations in C++?

Upvotes: 1

Related Questions