3

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

ここでは問題ありません。

更新: ヘッダー インクルージョンをガードに入れます (申し訳ありませんが、間違いでした)。

4

5 に答える 5

4

「宣言」だけを考えていると、話の半分が欠けています。C++ には、「クラス定義」という概念もあります。これは、3 番目の新しいタイプの動物です。これは、(クラスの)定義と (メンバー関数の)宣言の両方です。

クラスは(他の定義と同様に) 複数回定義できないため、クラス定義を含むヘッダー ファイルを複数回含めてはなりません。

にユーティリティ クラスFoofoo.hppあり、2 つの独立したモジュールがa.hppあり、b.hppどちらも が必要であるとしますFoo。メイン プログラムには と を含める必要がありa.hppますb.hppが、 を含めようとしているfoo.hppため、 のクラス定義がFoo2 回含まれています。

インクルード ガードを入力します。

于 2011-12-16T12:09:15.047 に答える
2

#include競合を恐れずに何度もヘッダーを作成できるためです。

1 レベルの入れ子がある場合は必要ありませんが、複数ある場合は必須です (h1 を含めることを検討してから、必要なため h1 を含む h2 を含めることを検討してください)。

于 2011-12-16T12:00:03.537 に答える
1

簡単な答えは、単にコンパイル速度です。GCC などのコンパイラは、ファイル全体のヘッダー ガードを検出し、それらのファイルが複数回検出された場合に読み取りと再処理を回避できます。ファイル全体をヘッダー ガードでラップしないと、ヘッダーが検出されるたびにコンパイラにヘッダーの再評価を強制する可能性が非常に高くなります。

于 2011-12-16T12:30:39.190 に答える
1

厳密にヘッダー ガードである場合は必要ありません。乗算が含まれている場合、宣言は既に表示されています。

これに対するもう 1 つの理由は、厳密なヘッダー ガードの外側で宣言を行うと、複数含まれるヘッダーに対するコンパイラの最適化が無効になる可能性があることです (つまり、ヘッダーが何度も開かれることになります)。

于 2011-12-16T11:59:37.513 に答える
1

あなたのシステムは循環的な包含から保護しません。例えば:

ヘッダー A:

#include "B.h"
#ifndef A_H_INCLUDED
#define A_H_INCLUDED
// ...
#endif // A_H_INCLUDED

ヘッダー B:

#include "A.h"
#ifndef B_H_INCLUDED
#define B_H_INCLUDED
// ...
#endif // B_H_INCLUDED

ソースファイル:

#include "A.h" // includes B, which includes A, which includes B, ...
于 2011-12-16T12:08:03.643 に答える