2010-12-08 9 views
3

クラスのコードが別のC++に配置されているのを見たことがありますが、メソッド定義はヘッダーファイルに配置されています。私の最初のOOP経験は、すべてのメソッドがクラスファイルに置かれているJavaであり、私は実際にこれを好む。.hと.cppファイルの間にメソッドを配置する

私のすべてのメソッドをヘッダファイルに配置することは、コンパイラによって生成されたアセンブリコードに影響するかどうかですか?

もしそうなら、クラスのコード全体をヘッダーファイルに配置することはパフォーマンスに全く悪影響を及ぼしますか?

答えて

2

ヘッダー/実装分割および 分割コンパイルのためのいくつかの正当な理由がありませ:
ジョブ要件でも1 - たとえば、あなたが誰かに バイナリライブラリ+ヘッダを供給している、またはあなたの同僚は他のものを受け入れるにはあまりにも保守的です 。
2.それぞれの変更後にアプリ全体を再構築するのは苦しいものになるため、依然として非常に大きなプロジェクト(ソースの10M以上)、つまり を開発する必要があります。 (ただし、jpeglibやzlibを1つのモジュールとしてコンパイルしても問題ありません)
3.参照用にヘッダファイルを使いやすく、 の機能をアップするという意見があります。 (ただし、通常、適切な文書を書く方が良い、ヘッダーとは異なり、文書のバグはプログラムに影響を与える可能性が低い)

また、これ以上使用しない理由はたくさんある:
1.あなたは重複したコードを維持しないようにします。
2.クラスメソッドは前方宣言を必要としません
3.テンプレートはヘッダーでのみとにかく宣言できます
4。関数インライン化を必要としない場合は、実際には非常にまれです。つまり、大きな関数をタイトループで何度も呼び出しているのですが、 のnoinline属性とPGOがあります。それ以外の場合、インライン展開は速度を向上させます。 そして、コードが肥大化すると、ほとんどのライブラリは既に巨大なものになっています。
5.全体的に、単一ソースとしてコンパイルされたプログラムは、コンパイラがより良い仕事をすることができるため、より小さくて小さくなります。 。
6.ヘッダーがないと、ソースは頻繁に約2倍小さくなります。 コンパイラは構文を正しくチェックできるため、 は誤ってextern "C" cdecl関数プロトタイプを変数にリンクできません実装として。 また、異なるリンカーは名前のマッチングに関する考え方が異なるため、全体としては移植性が高くなります。
7.その奇妙でダイナミックな割り当ては、 ヘッダースタイルのために頻繁に使用されます。 の詳細をすべて1つのクラスに定義すると自動的に依存関係を解決できますが、部分クラス宣言へのポインタメモリリークをハントする)。
4. gccのPGO統計は、オブジェクトモジュールごとに生成されます。これは、1つの実行可能ファイルでいくつかの異なる動作モードを「ベンチマーク」する唯一の方法と思われるものです。
5.速度最適化のために異なるコンパイラオプションを使用して異なるモジュールをコンパイルすることが可能です。コンパイラ拡張もいくつかありますが、あまり信頼性がありません。
6.何かを変更したときに、コンパイラはコードの別の部分に変わったことをすることがありますが、通常はオブジェクトモジュールの外側には伝播できません。

6

複雑なC++プログラムは、複数のオブジェクトをコンパイルしてから作成することがポイントです。各オブジェクトは、典型的には、1つの実装ファイル(例えば、 ".cpp"、 ".cc"など)をコンパイルした結果であり、多数のヘッダを直接的および間接的に含むことができる。したがって、良いクラスを作成してヘッダにヘッダを入れると、そのコードを複数のオブジェクトファイルに含めることができ、コンパイラが重複して生成することになります。さらに、リンカは(そして簡単には)比較できませんバージョンが同等であるかどうかを確認し、冗長コピーを削除します(相対アドレスを使用すると簡単です - 「位置独立コード」 - それは別の話です)。下記のjalfのコメントも参照してください。

したがって、ヘッダーに異なる行外機能を必要としません。インラインキーワードを使用するか、クラス内で定義されているため、コンパイラは余分な作業を行い、アウトラインバージョンが一意に表現されるようにするだけです実行可能ファイル。しかし、行外関数の場合、プログラマに負担が残ります。

さらに、ヘッダーに実装を提供すると、オブジェクトごとに重複してコンパイルされ、ヘッダーを変更するとすべてのオブジェクトが再コンパイルされます。別のオブジェクト内の行外関数を変更し、その単一のオブジェクトを再コンパイルし、他の既存のオブジェクトとリンクして新しい実行可能ファイルを作成することができます。大規模プロジェクトでは、多くのコンパイル時間が節約されます。

+1

+1私は本当にあなたの答えが好きです。しかし、好奇心の中で、あなたはテンプレートについてどのような考えをしていますか?私はテンプレートコードの多くが余分な "インライン"ヘッダーを含むか、またはメソッドの巨大な混乱のいずれかを見てきました。 – GWW

+1

@GWW:テンプレートはそれぞれのタイプの組み合わせごとにインスタンス化されるため、非常に高速で強力ですがクライアントコードに大きく依存します。 C++の歴史を通して、誰もヘッダーを介して "実装"を公開する必要性を避けるための良い方法を見つけました。 #includeを別のファイルにすると、クラス/構造体宣言の後に関数定義を置くのと同じようにAPIを分離しておくことがありますが、最適な結果は関数長、ドキュメントの量とスタイル、複雑さ、クライアントメンバと実装メンテナの比較)。それは*乱雑です:-) –

+0

リンカは、クラス定義の2つのインスタンスが同一であるかどうかを確認する必要はありません(リンカがないとわかりません)。彼らが同じ名前を持っているならば、それは典型的には同一であると仮定し、どちらか一方を削除します。その負担は、ODRに違反しないように常にプログラマにあります。 – jalf

1

はい、ヘッダーに配置されたメソッドはインライン展開されているため、一般的に高速です(特に短いもの)。

主な欠点は、ヘッダーを変更するたびに、それを含む各ファイルが再コンパイルされることです。

+0

"ヘッダーに置かれたメソッドはインライン展開されています" - 経験豊富なC++プログラマーのコードでは、それは当てはまりますが、初心者(例:seljuq70)はヘッダーに非インライン関数を入れることを間違えることがよくあります。技術的には、 'class' /' struct'の内部で定義された関数(すなわち本体のみ)、または 'inline'キーワードを指定する関数のみがインライン展開されます。それらはヘッダー内の唯一の関数であるべきですが、そうでないかもしれません。 –

+0

@トニー:だから私はあなたのより詳細な答えに投票した理由です。しかし、彼らは通常、多くの短い機能*を持つことをお勧めしていると考えています。 – ruslik

+0

まあ、私はそこにあなたの視点が好きです... "ヘッダーの簡単な機能"は初心者が使いすぎではなく、間違っていない簡単なガイドラインです - とにかくあなたの再コンパイルの説明でカバーされています。 –

関連する問題