質問
私はカップルのヘッダファイルを抜:
ます。h:
#include "element.h"
typedef struct tree_
{
struct *tree_ first_child;
struct *tree_ next_sibling;
int tag;
element *obj;
....
} tree;
と要素となります。h:
#include "tree.h"
typedef struct element_
{
tree *tree_parent;
char *name;
...
} element;
問題はその両方を参考に、お互いのでツリー要素を含む要素ツリーのニーズが含まれていた。
このなかで定義する'tree'の構造要素の構造既知のものを定義する要素構造は、ツリー構造ではないと考えられた。
をめぐる対立を解決するこれらの種類のループ(この場合には、あな進宣言"?)?
解決
ここでの問題は、インクルードガードが欠落していることではなく、2つの構造がその定義で互いに必要であるという事実だと思います。ですから、ハンと卵の問題を定義するタイプです。
CまたはC ++でこれらを解決する方法は、型に対して前方宣言を行うことです。要素が何らかの構造であることをコンパイラに伝えると、コンパイラはその要素へのポインタを生成できます。
E.g。
tree.h内:
// tell the compiler that element is a structure typedef:
typedef struct element_ element;
typedef struct tree_ tree;
struct tree_
{
tree *first_child;
tree *next_sibling;
int tag;
// now you can declare pointers to the structure.
element *obj;
};
そうすれば、tree.h内にelement.hを含める必要がなくなります。
ヘッダーファイルの周りにもinclude-guardを配置する必要があります。
他のヒント
重要な観測はこちらの要素は必要ありません知の構造をツリーでのみ有のポインタです。同じ。すべての各ニーズを知ることが存在するタイプの名前は何です。
できます。h,く:
#include "element.h"
:
typedef struct element_ element;
この"宣言"の"要素"と"struct element_"(ているとのこと)に属していることがわかっていない"の定義"しんか。すべての必要なお店のポインタをblahはblahしで宣言されていることで定義されています。みたい場合に畏敬の念で(例えば読みの会員だけの定義で設定します。コード".c"ファイルが必要となるが、この場合にはヘッダーになります。
一部の人をシングルのヘッダファイルのみを宣言し全ての種類のクラスターのヘッダをヘッダに含まれるのではなく、作る種類です。これは必須のものと全く愚かな.
その答えいなどについてはガードマンが違う良い方法が一般的だ読みつが設置されていることも自分の一部もあるんですが、その解決の問題です。
正しい答えは、インクルードガードを使用し、前方宣言を使用することです。
ガードを含める
/* begin foo.h */
#ifndef _FOO_H
#define _FOO_H
// Your code here
#endif
/* end foo.h */
Visual C ++は、#pragma onceもサポートしています。これは非標準のプリプロセッサディレクティブです。コンパイラの移植性と引き換えに、プリプロセッサ名の衝突の可能性を減らし、読みやすくします。
前方宣言
構造体を前方宣言します。構造体またはクラスのメンバーが明示的に必要でない場合、ヘッダーファイルの先頭でそれらの存在を宣言できます。
struct tree; /* element.h */
struct element; /* tree.h */
前方宣言について読んでください。
ie。
// tree.h:
#ifndef TREE_H
#define TREE_H
struct element;
struct tree
{
struct element *obj;
....
};
#endif
// element.h:
#ifndef ELEMENT_H
#define ELEMENT_H
struct tree;
struct element
{
struct tree *tree_parent;
...
};
#endif
インクルードガードは便利ですが、2つのデータ構造への再帰的な依存関係である投稿者の問題に対処しないでください。
ここでの解決策は、ヘッダーファイル内の構造体へのポインタとしてツリーや要素を宣言することです。そのため、.hを含める必要はありません
次のようなもの:
struct element_;
typedef struct element_ element;
tree.hの最上部は、element.hを含める必要をなくすのに十分なはずです
このような部分宣言では、コンパイラーがレイアウトについて何も知る必要のない要素ポインターでのみ実行できます。
最善の方法は、このようなループを避けることです。これらのループは回避すべき物理的カップリングの兆候であるためです。
例(覚えている限り)"オブジェクト指向設計ヒューリスティック" 循環(物理)依存関係のみをマスクするため、インクルードガードを回避する目的。
別のアプローチは、次のような構造体を事前宣言することです。
element.h:
struct tree_;
struct element_
{
struct tree_ *tree_parent;
char *name;
};
tree.h:
struct element_;
struct tree_
{
struct tree_* first_child;
struct tree_* next_sibling;
int tag;
struct element_ *obj;
};
Forward宣言は、後で定義される構造のタイプがあることを保証できる方法です。
前方宣言は、冗長でバグがあるため、好きではありません。すべての宣言を同じ場所に配置する場合は、インクルードガード付きのインクルードファイルとヘッダーファイルを使用する必要があります。
cプリプロセッサが#include行を見つけた場合、#include行が見つかった同じ場所にmyheader.hのコンテンツ全体を配置するだけで、インクルードをコピーペーストとして考える必要があります。
さて、インクルードガードを記述すると、myheader.hのコードは最初の#includeが見つかった場所に1回だけ貼り付けられます。
プログラムが複数のオブジェクトファイルでコンパイルされ、問題が解決しない場合は、すべてのオブジェクトファイルに対して型宣言のみを保持するために、オブジェクトファイル間で前方宣言を使用する必要があります(externを使用するようなものです)および識別子は一意である必要があります)。
簡単な解決策は、個別のヘッダーファイルを持たないことです。結局のところ、もしそれらが互いに依存しているなら、あなたはもう一方なしで一方を使うことは決してないでしょう。両方が同じヘッダーを使用するが、より焦点を絞った機能を提供する別々の.cファイルを持つことができます。
これはすべての派手なものを正しく使用する方法の質問には答えないことは知っていますが、同様の問題の簡単な修正を探していたときに役立ちました。