web-dev-qa-db-ja.com

ヘッダーファイルと実装(.cpp)ファイルでコンストラクタを定義する

クラスコンストラクターの本体は、クラス。hファイルまたは実装ファイル。cppで定義できます。コンパイラが特定のプロジェクトに関係している限り、これらの2つのスタイルはおそらく同一です(私にとってプロジェクトとは[〜#〜] dll [〜#〜]を意味します)。実際にはすべてのメンバー関数に同じことが当てはまります。ヘッダーファイルで定義するか、ヘッダーファイルで宣言してからcppファイルで定義することができます。

ただし、そのようなクラスヘッダーファイルを別のプロジェクトに含める必要がある場合(最終的には、ヘッダーファイルを使用するコードは別の[〜#〜] dll [〜#〜 ])ヘッダーファイルに実際の実装があると、コンパイル時に頭痛の種になります(リンク時ではなく、その点にさえ到達しません)。どうして?あまり詳しくはしませんが、コンパイラーは明らかに他のヘッダーファイルなどで定義されている可能性のあるすべての関数を解決しようとし、貧しい開発者にさまざまなヘッダーファイルなどの取り込みを強制します。

ヘッダーファイルを実装せず、単に「宣言」に使用するのが常に最善ではありませんか?それにより、多くの余分なジャンクを持ち歩く必要がない複数のプロジェクトにそれらを含めるのが簡単になります。

これについてあなたはどう思いますか?

29
Andrea

実装をインライン化する場合を除き、ヘッダーに実装を含めないでください(例:些細なゲッター/セッター)。もちろん、テンプレートでない限り。

コンストラクターの例外を作成する理由はありません。それらを.cppファイルに入れます。

27
Thomas

注意すべき重要な点は、メンバー関数がヘッダーファイル内で定義されている場合、クラス本体内にあるか、inlineとして明示的にマークされている必要があることです。つまり、ヘッダーファイルでこれを行うのは明らかに間違っています。

class A {
  public:
    A();
};

A::A() {
  // constructor body
}

間違っている理由は、コンパイラが各コンパイル単位に定義を含めるようにするためです。一方、関数は一度だけ定義する必要があることは明らかです。同じことを行う正しい方法は次のとおりです。

class A {
  public:
    inline A();
};

inline A::A() {
  // constructor body
}

または:

class A {
  public:
    inline A() { // inline isn't required here, but it's a good style
     // constructor body
    }
};

どちらの場合も、コンストラクターはインラインです。これを通常のアウトライン関数にする唯一の正しい方法は、ヘッダーではなく実装ファイルで定義することです。これは、これら2つのアプローチの最も重要な違いです。

さて、インライン化が最適化であることは注目に値します。そして、最適化と同様に、それらは必要であると判明するまで避けるのが最善です。インライン化につながる可能性のある他の問題には、互換性の問題があります:インライン化されていない関数の本体を変更する場合、定義されているユニットを再コンパイルするだけで、誰でもすぐに新しい実装の使用を開始できます。インライン関数を使用すると、関連するヘッダーを含むすべてのユニットを再コンパイルする必要があります。これは、特にさまざまな人々がさまざまなプロジェクトでヘッダーを使用している場合は苦痛です。

つまり、特定の関数呼び出しがパフォーマンスのボトルネックであることをプロファイリングによって証明されるまで、可能な限り通常の表外定義を使用します。このルールの唯一の合理的な例外は、取るに足らないセッターとゲッターであり、それらを使用する場合でも注意することをお勧めします-いつかは自明ではなくなり、多くの再コンパイルと互換性の破壊を意味します。

25
Sergei Tachenov

考慮すべき別の注意事項:ヘッダーファイルを変更するには、そのヘッダーファイルを含むすべてのファイルを再構築する必要があります。ほとんどのビルドシステムは、変更されたヘッダーファイルに依存するソース(* .cpp/.cc)ファイルを再構築します。

ヘッダーファイルで定義されているクラスのメソッドを変更すると、ヘッダーファイルを含むすべてのソースファイルが再構築されます。ソースファイルのメソッドを変更すると、ソースファイルのみが再構築されます。これは、中規模から大規模のプロジェクトで問題になる可能性があります。

ビルドプロセスを簡素化するには、クラスのほとんどのメソッドをソースファイルで定義する必要があります。小さなメソッドやインライン化のその他の候補は、ヘッダーファイルで定義する必要があります。

1
Thomas Matthews