C と C++ では、宣言と定義が区別されます。
シンボルは何度でも宣言できますが、定義できるのは 1 回だけです。これを学ぶことで、宣言をガードの外側に置き、定義をガードの内側に置くという考えがあります。
// declarations
int foo(int x, int y);
int bar(int x, int y);
extern double something;
class X;
#ifndef _MY_HEADER_H_
#define _MY_HEADER_H_
#include "otherheader1.h"
#include "otherheader2.h"
// definitions of structures, classes.
class X
{
// blah blah...
};
#endif
このようにして、ヘッダーを任意の順序で含めることができます。おそらく、循環依存関係は問題になりません。
では、宣言を外部に置くことができるのに、なぜヘッダー全体をガード トークンで保護するのでしょうか?
私の根拠は次のとおりでした。
2 つのヘッダーが何らかの形で相互に参照している場合、問題が発生することがよくあります。通常、宣言されていないシンボルエラーが発生し、最初の反射は必要なヘッダーを含めることです。しかし、2 つのヘッダーがたまたまお互いに含まれていると、不可解なエラーが発生します。
ああ:
#ifndef A_H
#define A_H
#include "b.h"
class A {B *b;}
#endif
bh
#ifndef B_H
#define B_H
#include "a.h"
class B {A *a;}
#endif
b.cpp に bh を含めると、ah で B が宣言されていないが、ヘッダーが含まれているというエラーが表示されます。(それはwtfの瞬間です。)
これは、ヘッダー ガードがネストされないためです。
#ifndef B_H
#define B_H
#ifndef A_H
#define A_H
// B_H already defined no include here.
class A {B *b;}
#endif
class B {A *a;}
#endif
宣言をガードの外に置くと、これを防ぐことができます。
class B; // in b.h
#ifndef B_H
#define B_H
class A; // in a.h
#ifndef A_H
#define A_H
class B; // again from b.h
// B_H already defined no include here, no redefinition.
class A {B *b;}
#endif
class B {A *a;}
#endif
ここでは問題ありません。
更新: ヘッダー インクルージョンをガードに入れます (申し訳ありませんが、間違いでした)。