game.h needs:
- packet.h
- socket.h
server.h needs:
- socket.h
socket.h needs:
- game.h
socket.h には game.h が既に含まれているため、socket.h を game.h に含めようとすると問題が発生します。このような問題を解決するにはどうすればよいですか?
game.h needs:
- packet.h
- socket.h
server.h needs:
- socket.h
socket.h needs:
- game.h
socket.h には game.h が既に含まれているため、socket.h を game.h に含めようとすると問題が発生します。このような問題を解決するにはどうすればよいですか?
通常の方法では、ヘッダー ファイルで #ifdef と #define を使用します。
game.h 内:
#ifndef GAME_H
#define GAME_H
.. rest of your header file here
#endif
このように、コンテンツは複数回読み取られますが、定義は 1 回だけです。
編集:コメントごとに識別子の先頭と末尾にあるアンダースコアを削除しました。
鍵は前方宣言です。(またはその逆) でgame.h
必要なものを取得し、さらに別のヘッダーで前方宣言します。例として、次のことを考慮してください。socket.h
game_forwards.h
// game_fwd.h
#ifndef GAME_FWD_H
#define GAME_FWD_H
class game;
#endif // ndef GAME_FWD_H
// game.h
#ifndef GAME_H
#define GAME_H
#include "socket.h"
class game {
socket* m_sck;
};
#endif // ndef GAME_H
// socket.h
#ifndef SOCKET_H
#define SOCKET_H
#include "game_fwd.h"
class socket {
game* m_game;
};
#endif // ndef SOCKET_H
明らかに、これが機能するためには、インターフェースと実装を分離することが重要です。
テクニック(フォワード定義とread-onceヘッダー)に加えて、ソケットヘッダーがゲームヘッダーから何かを必要とする理由を解明し、単一の依存関係の順序でシステムをモジュールにパッケージ化する必要があります。ソケットクラスがどのゲームに使用されているかを知る必要がある理由はないはずです。
完全を期すために、別の代替手段は次のとおりです。
#pragma once
ファイルの上部にあります。
これには、ファイルが繰り返し開かれず、コンパイル時間が節約されるという利点があります。
標準ではないという欠点があるため、すべてのコンパイラがサポートしているわけではありません。Visual C++ で確実に動作します。
私が考えることができるエレガントな方法はありません-あなたの最善の策は、実際に使用される関数を前方定義することです. したがって、game.h が socket.h の connect() 関数のみを使用する場合は、次の行を game.h に追加します。
void connect();
そして、socket.h インポートを削除します。もちろん、connect() の署名が変更された場合は、前方定義も更新することを忘れないでください。そのため、このソリューションは理想とはほど遠いものです。可能であれば、設計を変更して循環依存を回避してください。
game.h が socket.h 内のクラスについて知る必要があるだけの場合は、次のように前方定義します。
class Socket;
インライン関数とメンバー オブジェクトに関しては、いくつかの注意事項があります。 The C++ FAQ Liteを参照してください。
@lassevk、「ヘッダーファイルは数回開かれますが、プリプロセッサは最初の読み取り中に #ifndef と #endif の間のファイルの内容のみを読み取ります。その後、プリプロセッサは bewteen を無視します。 _GAME_H が定義されているため、PP マクロ。