web-dev-qa-db-ja.com

C ++クラスヘッダーファイルの構成

複数のソースファイルとヘッダーファイルにまたがる多数の相互依存クラスを処理する必要がある人に提案するC++コーディングとファイル編成のガイドラインは何ですか?

私のプロジェクトにはこのような状況があり、複数のヘッダーファイルをまたぐクラス定義関連のエラーを解決するのは非常に頭痛の種になっています。

50
Ashwin Nanjappa

一般的なガイドライン:

  • インターフェイスと実装をペアにします。 foo.cxxがある場合、そこで定義されているものはすべてfoo.hで宣言することをお勧めします。
  • すべてのヘッダーファイルに、独立したコンパイルに必要な他の必要なヘッダーまたは前方宣言がすべて含まれていることを確認します。
  • 「すべて」のヘッダーを作成するという誘惑に抵抗します。彼らは常に問題を抱えています。
  • 関連する(相互に依存する)機能のセットを1つのファイルに入れます。 Javaおよびその他の環境では、ファイルごとに1つのクラスが推奨されます。C++では、多くの場合、ファイルごとに1つのset ofクラスが必要です。これは、コードの構造によって異なります。
  • 可能な限り、#includesよりも宣言を転送することをお勧めします。これにより、循環ヘッダーの依存関係を解除できます。基本的に、別々のファイルにまたがる循環的な依存関係の場合、次のようなファイル依存関係グラフが必要です。
    • A.cxxにはA.hB.hが必要です
    • B.cxxにはA.hB.hが必要です
    • A.hにはB.hが必要です
    • B.hは独立しています(およびA.hで定義されたクラスを前方宣言します)

コードが他の開発者が使用するライブラリを意図している場合、実行することが重要な追加の手順がいくつかあります。

  • 必要に応じて、「プライベートヘッダー」の概念を使用します。つまり、いくつかのソースファイルには必要ですが、パブリックインターフェイスには必要ないヘッダーファイルです。これは、一般的なインライン関数、マクロ、または内部定数を含むファイルである可能性があります。
  • ファイルシステムレベルで、パブリックインターフェイスをプライベート実装から分離します。 CまたはC++プロジェクトでは、include/およびsrc/サブディレクトリを使用する傾向があります。ここで、include/にはすべてのパブリックヘッダーがあり、src/にはすべてのソースがあります。プライベートヘッダー。

John Lakosの本Large-Scale C++ Software Designのコピーを見つけることをお勧めします。かなり高額な本ですが、物理アーキテクチャに関する彼の議論のいくつかをざっと見れば、たくさん学ぶことができます。

66
Tom

NASA Goddard Space Flight Center でCおよびC++コーディング標準を確認してください。私がC標準で特別に指摘し、自分のコードで採用した1つのルールは、ヘッダーファイルの「スタンドアロン」の性質を強制するものです。ヘッダーxxx.hの実装ファイルxxx.cppで、含まれる最初のヘッダーがxxx.hであることを確認します。ヘッダーが自己完結型でない場合、コンパイルは失敗します。それは美しくシンプルで効果的なルールです。

失敗するのは、マシン間で移植した場合のみで、xxx.hヘッダーには、たとえば<pqr.h>が含まれますが、<pqr.h>には、元のプラットフォームのヘッダー<abc.h>によって利用可能になる機能が必要です(つまり、<pqr.h>には<abc.h>が含まれます)。ただし、他のプラットフォームの<abc.h>では、この機能を利用できません(代わりにdef.hにありますが、<pqr.h>には<def.h>が含まれていません)。これはルールの誤りではなく、ルールに従うと問題の診断と修正がより簡単になります。

8
6
yesraaj

トムの答え は素晴らしいものです!

私が追加する唯一のことは、ヘッダーファイルで「宣言を使用」しないことです。それらは実装ファイルでのみ許可されるべきです。 foo.cpp

このロジックは、優れた書籍「Accelerated C++」( Amazonリンク -スクリプトキディリンクナチス向けにサニタイズ)で詳しく説明されています

5
Rob Wells

私はしばしば見捨てられている非常に良い習慣を1つ追加したいと思います(CとC++の両方で):

foo.c

#include "foo.h" // always the first directive

他の必要なヘッダーが続き、コードを記述します。重要なのは、とにかくこのコンパイルユニットのヘッダーがほとんど常に必要であり、最初のディレクティブとしてヘッダーを含めるとヘッダーが十分であることを保証することです(そうでない場合、エラーが発生します)。これは特にパブリックヘッダーに当てはまります。

このヘッダーインクルードの前に何かを置く必要がある場合(もちろん、コメントを除く)、何か間違っている可能性があります。あなたが本当にあなたが何をしているのかを知らない限り...それは別のより重要なルールにつながります=>あなたのハックをコメントしてください!

3
Alex

ここで他のポイントに加えてもう1つポイント:

インクルードファイルにプライベート定義を含めないでください。例えば。 xxx.cppでのみ使用される定義は、xxx.hではなくxxx.cppである必要があります。

当たり前のようですが、よく目にします。

3
Steve Fallows