2009-05-17 12 views
14

私は、クラスを.hと.cppファイルに分割する全体のポイントは何ですか?それは編集するのが難しくなります。クラスが外部で使用するために.libまたは.dllにコンパイルされない場合、何がポイントですか?C++でクラス宣言と定義を2つの別々のファイルに置くのはなぜですか?

編集: 私はBoostライブラリはすべてを.hppファイル(ライブラリの大部分はとにかく)に入れているので、他のほとんどのコードでそれが分離されている理由を知りたいと思っていました。そうですか。

答えて

15

C++には1つの定義ルールがあります。つまり、(インライン関数を除く)定義は、1つのコンパイル単位にしか現れません。 C++ヘッダーファイルはすべてのインクルードファイルで「コピー&ペースト」されているだけなので、ヘッダーファイルに定義を入れるだけで複数の場所に定義を入れています。

もちろん、すべてをインラインにしないでください。コンパイラがインライン提案を尊重していると、長い関数のコードがすべての呼び出しサイトで複製され、コードが大きくなりすぎて、スラッシングやキャッシュの問題など、さまざまな問題が発生する可能性があります。

一方、コンパイラがあなたの話を聞いておらず、何もインライン化していない場合は、次の2つの問題があります。1)クラス定義を取得した翻訳単位がわからない。コンパイラは#includeするたびにあなたの定義を辿る必要があります。さらに、同じメソッドを誤って2つの異なるヘッダーで2回定義していないことを確認する簡単な方法はありません。

また、循環依存関係の問題も発生します。クラスが別のクラスのメソッドを呼び出すには、そのクラスを最初に宣言する必要があります。したがって、2つのクラスがお互いのメソッドを呼び出す必要がある場合は、それぞれを宣言してからどちらかを定義する必要があります。宣言と定義を1つのファイルで行う方法はありません。

本当に、それはどのように言語とパーサが構築されたかです。それは痛みですが、あなたはそれに対処しなければなりません。

0

ほとんどの場合、クラスを実装するファイルのほかにクラスを使用する必要があるためです。プログラム全体を1つのファイルにまとめると、分離する必要はありません。

C++プログラムをすべて1つのファイルに書くことはほとんどありません。

+0

私は、クラス定義全体を.hに入れ、それを含め、ヘッダガードで保護します。 –

+0

.hファイルを同じ実行可能ファイルの複数の場所に含めるとどうなりますか? Ans:あなたは同じ関数の複数の定義で終わります。 - 実際のところここでのポイントは、ルールであらゆる種類の愚かなことをすることができるということですが、実際には通常の方法と同じようにほとんどうまく機能しません。 –

3

このようにコードを持つ利点の1つは、コンパイル時間を短縮できることです。

のは、あなたのプロジェクトにこれらのファイルを持っているとしましょう:

  • ああ
  • a.cpp
  • b.cpp

すでにa.cppは、オブジェクトにコンパイルしている場合ファイルaoの場合、ahb.cppに含めると、パーザはの宣言/定義全体を処理する必要がないので、より迅速になるはずです。

2

DLL内であっても、他のクラスでもクラスが使用されるためです。これらのファイルは、コンパイル時に.hをインクルードしてクラス宣言を参照する必要があります。彼らは定義を見てはいけません、またはクラス関数の複数の定義があります。

0

C++では、コードモジュール(.cまたは.cppファイル)を別々にコンパイルするには、関数プロトタイプを使用前に定義する必要があります。他の場所で定義されたクラスやメソッドを使用する場合は、定義を取得するために.hファイルをインポートする必要があります。結局、リンカは.hファイルで行われたすべての約束がすべてのc/cppファイルによって確実に実行できるようにします。

また、.hファイルを定義するだけでboostなどのフレームワーク全体を作成することもできます。

#ifndef _STDIO_H_ 
.... 
#define _STDIO_H_ 
.... 
#endif /* _STDIO_H_ */ 

乾杯:

+1

Boostは、ほとんどがC++テンプレートに大きく依存しているのでヘッダファイルで構成されています(テンプレート化されている場合はクラス定義全体をヘッダーに入れることを意味します)。限り、私はこのフレームワークのいくつかの部分がcppファイルを持っていることを覚えています。これは、C++テンプレートに依存しないものです。例えばスレッドライブラリです。 –

2

あなたの編集re:Boostは重要な区別をします。テンプレートクラスは、コンパイラとリンカーが現在のC++標準で動作する方法のため、ほとんどの場合ヘッダーで定義されます。 Boostだけでなく、ほとんどのテンプレートライブラリが同じ理由でヘッダファイルに実装されています。

5

ブーストはすべてのコードをインライン化していません。 shared_ptrのように、コンシューマがインスタンス化することを期待するクラスのテンプレート定義をインライン化します。多くのライブラリには、boost :: serializationやprogram_optionsのように、別々にコンパイルする必要のあるセクションがあります。

コードベースのサイズが大きくなると、インライン展開が深刻な悪影響を受ける可能性があります。あなたのコンパイル時間を間違えないように、あなたのコンポーネント間のカップリングを増やします(他の多くの理由のために、これを高めることができます:)。効果的には、翻訳単位のすべてにプログラムのほぼ完全なコピーがあり、小さな変更はすべてを再構築/再テストする原因になります。プロジェクトによっては、何時間もかかることがあります。

私はそれを編集するのが難しいことに本当に気づいたことはありません。私の経験では、インターフェイスと実装がはっきりと分かれているために簡単になりました。私が探しているものを見つけるためにどのファイルを使用するのか知っています。

+0

良い答え!実装の一部がプライベートデータフィールドの形式でヘッダーにリークするため、残念ながらインターフェイスと実装の分離が望ましくないほど明確ではありません(そうしなければ、コンパイラはクラスのサイズ)。この問題に対処するために、pimplイディオムが使用されます。 –

関連する問題