web-dev-qa-db-ja.com

ヘッダーファイルの循環依存関係の回避

ヘッダーファイルの循環依存関係を回避する方法について、良いアドバイスはありますか?

もちろん、最初からプロジェクトをできるだけ透明にしようとしています。ただし、より多くの機能とクラスが追加され、プロジェクトの透明性が低下すると、循環的な依存関係が発生し始めます。

一般的、検証済み、および機能するルールはありますか?ありがとう。

50
Bunkai.Satori

循環依存がある場合は、何か間違ったことをしていることになります。

例として:

foo.h
-----
class foo {
public:
   bar b;
};

bar.h
-----
class bar {
public:
   foo f;
};

おそらく違法です:

foo.h
-----
class bar; // forward declaration
class foo {
   ...
   bar *b;
   ...
};

bar.h
-----
class foo; // forward declaration
class bar {
   ...
   foo *f;
   ...
};

そしてこれは大丈夫です。

一般的なルール:

  1. 各ヘッダーを単独で含めることができることを確認してください。
  2. 前方宣言を使用できる場合は、それらを使用してください!
49
Artyom
  • 可能な場合は、前方宣言を使用します。
  • Cppファイルでのみ必要な場合は、ヘッダーインクルードをヘッダーファイルから対応するcppファイルに移動します。これを強制する最も簡単な方法は、#include "myclass.h"最初のインクルードmyclass.cpp
  • 別々のクラス間の相互作用の時点でインターフェースを導入すると、依存関係を減らすのに役立ちます。
15
jon-hanson

循環依存を避けるために私が従ういくつかのベストプラクティスは、

  1. OOADの原則に固執します。含まれているクラスが現在のクラスと構成関係にない限り、ヘッダーファイルを含めないでください。代わりに前方宣言を使用してください。
  2. 2つのクラスのインターフェイスとして機能する抽象クラスを設計します。そのインターフェースを介してクラスの相互作用を行います。
7
Sulla

一般的なアプローチは、2つの元のヘッダーファイルによって参照される3番目のヘッダーファイルに共通性を除外することです。

循環依存のベストプラクティス も参照してください。

6
Ed Guiness

プリプロセッサ機能に応じて:

#pragma once

または

#ifndef MY_HEADER_H
#define MY_HEADER_H
your header file
#endif

ヘッダーファイルを設計するのが非常に退屈だと思う場合は、Hwaci(SQLiteおよびFossil DVCSの設計者)の makeheaders が役に立つかもしれません。

4
Benoit

一般に、ヘッダーファイルは、可能な限り他のヘッダーを含めるのではなく、前方宣言する必要があります。

また、ヘッダーごとに1つのクラスを使用するようにしてください。

そうすれば、ほぼ間違いなく間違いはありません。

最悪のカップリングは通常、肥大化したテンプレートコードから生じます。定義をヘッダーに含める必要があるため、多くの場合、すべての種類のヘッダーを含める必要があり、テンプレートを使用するクラスには、他のものの負荷を含むテンプレートヘッダーが含まれます。

この理由から、私は一般的に言うでしょう:テンプレートに注意してください!理想的には、テンプレートの実装コードに何も含める必要はありません。

3
CashCow

あなたが目指しているのは、階層化アプローチです。モジュールが下位層モジュールに依存できる層を定義できますが、その逆はobserversで行う必要があります。これで、レイヤーの粒度と、レイヤー内で循環依存関係を受け入れるかどうかを定義できますが、この場合は this を使用します。

3
stefaanv

Altough Artyomは、このチュートリアルも優れた拡張機能を提供するこのチュートリアルも素晴らしい回答を提供しました http://www.cplusplus.com/forum/articles/10627/

2
rank1