パート2.ヘッダーファイル
...
コードを書くとき、私たちは皆、コードフォーマットのルールを使用します。ルールが考案されることもあれば、既製のスタイルガイドが使用されることもあります。すべてのC ++プログラマーはネイティブよりも英語を読みやすいですが、ネイティブよりもマニュアルがある方が良いでしょう。
この記事は、GoogleのC ++スタイルガイドの一部をロシア語に翻訳したものです。
元の記事(githubのフォーク)、更新された翻訳。
ヘッダーファイル
各.ccソースファイルには、一致する.hヘッダーファイルがあることが望ましいです。ユニットテストやmain()関数のみを含む小さな.ccファイルなど、このルールには既知の例外もあります。 ヘッダーファイルを正しく使用すると、コードの読みやすさ、サイズ、パフォーマンスに大きな影響を与える可能性があります。 次のルールは、ヘッダーファイルに関する頻繁な問題を回避するのに役立ちます。
独立したヘッダーファイル
ヘッダーファイルは(コンパイルに関して)自給自足であり、拡張子が.hである必要があります。コードに含めることを目的としたその他の(ヘッダー以外の)ファイルは、拡張子が.incであり、インクルードコードとペアになっている必要があります。
すべてのヘッダーファイルは自己完結型である必要があります。ユーザーと開発ツールは、ヘッダーファイルを使用するときに特別な依存関係に依存しないでください。ヘッダーファイルはロック可能であり、必要なすべてのファイルが含まれている必要があります。
テンプレートとインライン関数の定義を、それらの宣言と同じファイルに配置することをお勧めします。そして、これらの定義はすべての.ccに含まれている必要がありますそれらを使用してファイルします。そうしないと、一部のビルド構成でリンクエラーが発生する可能性があります。宣言と定義が異なるファイルにある場合は、一方を含めてもう一方を含める必要があります。定義を個別のヘッダーファイル(-inl.h)に分割しないでください。以前は、この方法は非常に人気がありましたが、現在は望ましくありません。
例外として、テンプレート引数の使用可能なすべてのバリアントがテンプレートから作成される場合、またはテンプレートが1つのクラスのみで使用される機能を実装する場合、このテンプレートが使用される1つ(および1つのみ)の.ccファイルでテンプレートを定義できます。
ヘッダーファイルが自己完結型でないまれな状況があります。これは、ファイルが別のファイルの途中など、非標準の場所に含まれている場合に発生する可能性があります。この場合、再有効化ロックがない可能性があり、追加のヘッダーファイルも含まれていない可能性があります。このようなファイルには、拡張子が.incの名前を付けます。それらをペアで使用し、一般的な要件にできるだけ一致するようにしてください。
ロックを再開します
すべてのヘッダーファイルは、再包含から#define保護されている必要があります。マクロ定義の形式は、<PROJECT> _ <PATH> _ <FILE> _H_である必要があります。
一意性を確保するには、プロジェクトツリーで完全なファイルパスコンポーネントを使用します。たとえば、プロジェクトfooのファイルfoo / src / bar / baz.hには、次のロックがあります。
#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...
#endif // FOO_BAR_BAZ_H_
予告
可能であれば、事前のお知らせは使用しないでください。#代わりに必要なヘッダーファイルを含めます。
定義
「事前宣言」は、対応する定義のないクラス、関数、テンプレートの宣言です。
あたり
- . #include ( ) .
- . #include - .
- , .
- API, . , API: , , .
- std:: .
- , : #include. , #include ( ) :
// b.h: struct B {}; struct D : B {}; // good_user.cc: #include "b.h" void f(B*); void f(void*); void test(D* x) { f(x); } // calls f(B*)
#include B D, test() f(void*). - , .
- 予備宣言(さらに、クラスメンバーとしてのポインターの使用)を可能にするコード構造は、コードを混乱させ、遅くする可能性があります。
評決
- 別のプロジェクトで宣言されたエンティティを事前に宣言しないようにしてください。
- ヘッダーファイルで宣言された関数を使用する場合は、常にそのファイルを#includeしてください。
- クラステンプレートを使用する場合は、そのヘッダーファイルを#includeすることをお勧めします。
名前と含める順序に含める ためのルールも参照してください。
インライン機能
関数をインライン関数として定義するのは、関数が小さい場合、たとえば10行以下の場合のみです。
定義
関数をインラインとして宣言し、関数を呼び出す標準的な方法に加えて、呼び出し元のコードに関数を直接含めるようにコンパイラーに指示できます。
長所
インライン関数を使用すると、特に関数が小さい場合に、より効率的なコードを生成できます。この機能は、get / set関数、その他の短くてパフォーマンスが重要な関数に使用します。
に対して
インライン関数を使いすぎると、プログラムが遅くなる可能性があります。また、インライン関数は、そのサイズに応じて、コードのサイズを増減できます。これらが小さな関数である場合、コードを最小化できます。関数が大きい場合、コードサイズが非常に大きくなる可能性があります。最近のプロセッサでは、命令キャッシュをより適切に使用するため、よりスリムなコードの実行が高速になることに注意してください。
評決
10行を超えるコードの場合、関数をインライン化しないことをお勧めします。デストラクタをインライン化しないでください。それらは暗黙的に多くの追加コードを含むことができます:変数デストラクタと基本クラスへの呼び出し!
もう1つの良い目安は、ループまたはスイッチステートメントを持つ関数をインライン化することは通常意味がないということです(ループまたは他のステートメントが実行されない縮退した場合を除く)。
インライン関数が必ずしもこの方法でコードにコンパイルされるとは限らないことを理解することが重要です。たとえば、通常、仮想関数と再帰関数は標準の呼び出しでコンパイルされます。一般に、再帰関数はインライン関数として宣言しないでください。インライン仮想関数を実行する主な理由は、定義(コード)をクラス定義自体に(動作または読みやすさを文書化するために)配置することです。これは、get / set関数によく使用されます。
名前と注文を含める
ヘッダーファイルを次の順序で挿入します:ペアファイル(たとえば、foo.h --foo.cc)、Cシステムファイル、C ++標準ライブラリ、その他のライブラリ、プロジェクトファイル。
すべてのプロジェクトヘッダーは、などのUNIXエイリアスを使用せずに、プロジェクトソースディレクトリから相対的である必要があります。(現在のディレクトリ)または..(親ディレクトリ)。たとえば、google-awesome-project / src / base /logging.hは次のように含める必要があります。
#include "base/logging.h"
別の例としての主な機能場合DIR / foo.ccとDIR / foo_test.ccファイルがで宣言されたコードを実装し、テストすることであるDIR2 / foo2.h、次の順序でヘッダファイルを書き込みます。
- dir2 /foo2.h。
- —
- C (: .h), <unistd.h>, <stdlib.h>.
- —
- C++ ( ), <algorithm>, <cstddef>.
- —
- .h .
- .h .
ファイルの各(空ではない)グループを空の行で区切ります。
このファイルの順序により、ペアのヘッダーファイル(dir2 / foo2.h)に必要なヘッダーファイル(システムなど)がなく、対応するdir /foo.ccまたはdir / foo_test.ccファイルのアセンブリが失敗した場合のエラーを検出できます。その結果、エラーはこれらのファイルを操作している開発者にすぐに表示されます(外部ライブラリのみを使用する別のチームには表示されません)。
通常、ペアのファイルdir /foo.ccとdir2 / foo2.hは同じディレクトリ(たとえば、base /basictypes_test.ccとbase / basictypes.h)にありますが、これは必須ではありません。
stddef.h などのCヘッダーファイルは通常、対応するC ++ファイル(cstddef)と交換可能であることに注意してください。任意のバリエーションを使用できますが、既存のコードのスタイルに従うのが最善です。
各セクション内で、ヘッダーファイルはアルファベット順にリストするのが最適です。以前に記述されたコードはこの規則に従わない場合があることに注意してください。可能であれば(たとえば、ファイルを修正する場合)、ファイルの順序を正しい順序に修正します。以前に宣言さ
れた場合を除き、必要なタイプを宣言するすべてのヘッダーファイルを含める必要があります。コードでbar.hの型を使用している場合は、別のファイルfoo.hに依存してbar.hを含めないでください。そして、foo.hのみを含めるように制限することができます:明示的にbar.hを含めます(foo.hがbar.hからの型も提供することが明示的に(おそらくドキュメントで)述べられていない限り)。 たとえば、google-awesome-project / src / foo / internal /fooserver.ccのヘッダーファイルのリストは次のようになります。
#include "foo/server/fooserver.h"
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/commandlineflags.h"
#include "foo/server/bar.h"
例外
プリプロセッサの状態によっては(使用するOSによっては)、ヘッダーファイルを含める必要がある場合があります。このようなインクルードをできるだけ短く(ローカライズ)して、他のヘッダーファイルの後に配置するようにしてください。例えば:
#include "foo/public/fooserver.h"
#include "base/port.h" // For LANG_CXX11.
#ifdef LANG_CXX11
#include <initializer_list>
#endif // LANG_CXX11
注:オープンソース
から取得した画像。