web-dev-qa-db-ja.com

C ++のどこに「含める」べきか

私はいくつかのc ++コードを読んでいて、ヘッダーファイルと.cppファイルの両方に「#include」があることに注意してください。ファイル内のすべての「#include」を移動すると、たとえばfoo.cppもそのヘッダーファイルfoo.hhに移動し、foo.cppにfoo.hhのみをインクルードさせると、コードは次のような問題を考慮せずに機能するはずです。欠点、効率など。

私の「突然の」アイデアは何らかの形で悪いアイデアであるに違いないことを私は知っていますが、それの正確な欠点は何ですか?私はc ++を初めて使用するので、この質問に自分で答える前に、C++の本をたくさん読みたくありません。だからあなたの助けのためにここに質問をドロップしてください。前もって感謝します。

28
Haiyuan Zhang

原則として、インクルードは可能な場合は.cppファイルに入れ、それが不可能な場合は.hファイルにのみ入れてください。

多くの場合、 前方宣言 を使用して、他のヘッダーからヘッダーを含める必要をなくすことができます。これにより、プロジェクトの成長に伴って大きな問題になる可能性のあるコンパイル時間を短縮できます。後日(すでに問題が発生している場合)に整理しようとすると、完全に悪夢になる可能性があるため、これは早い段階で始めるのに適した習慣です。

このルールの例外は、テンプレート化されたクラス(または関数)です。それらを使用するには、完全な定義を確認する必要があります。これは通常、ヘッダーファイルに配置することを意味します。

33
jkp

ヘッダー内のインクルードファイルは、そのヘッダーをサポートするために必要なファイルのみである必要があります。たとえば、ヘッダーでベクトルが宣言されている場合は、ベクトルを含める必要がありますが、文字列を含める理由はありません。その単一のヘッダーファイルのみを含み、コンパイルされる空のプログラムを持つことができるはずです。

もちろん、ソースコード内では、呼び出すすべてのものにインクルードが必要です。どのヘッダーもiostreamを必要としないが、実際のソースに必要な場合は、個別に含める必要があります。

インクルードファイルの汚染は、私の意見では、コード腐敗の最悪の形態の1つです。

編集:へー。パーサーが>記号と<記号を食べているように見えます。

14
jfawcett

ヘッダーファイルを含む他のすべてのファイルに、ヘッダー内のすべての#includeも推移的に含めるようにします。

C++では(Cと同様)、#includeは、#includeステートメントの代わりに#includedファイルにすべてのテキストを挿入するだけでプリプロセッサによって処理されます。したがって、#includeがたくさんあると、コンパイル可能なファイルのサイズを文字通り数百キロバイトまで自慢できます。コンパイラは、すべてのファイルについてこれをすべて解析する必要があります。異なる場所に含まれている同じファイルは、#includedであるすべての場所で再解析する必要があることに注意してください。これにより、コンパイルが遅くなり、クロールする可能性があります。

ヘッダーで宣言する必要がある(定義しない)必要がある場合は、#includesの代わりに 前方宣言 を使用してください。

6
Péter Török

ヘッダーファイルには必要なものだけを含める必要がありますが、「必要なもの」は想像以上に流動的であり、ヘッダーを配置する目的によって異なります。これが意味するのは、一部のヘッダーは実際にはライブラリやその他のコードのインターフェイスドキュメントであるということです。そのような場合、ヘッダーには、ライブラリを正しく使用するために別の開発者が必要とするすべてのものを含める必要があります(おそらく#include)。

2
Liz Albin

.hh(または.h)ファイルは宣言用であると想定されています。

.cpp(または.cc)ファイルは、定義と実装用であると想定されています。

まず、#includeステートメントがliteralであることを認識してください。 _#include "foo.h"_は、文字通りfoo.hの内容をコピーし、includeディレクティブが他のファイルにある場所に貼り付けます。

他のいくつかのファイルbar.cppおよびbaz.cppは、foo.ccに存在するコードを利用したい場合があるという考えです。これを行う方法は、通常、bar.cppとbaz.cppを_#include "foo.h"_に送信して、使用したい関数またはクラスの宣言を取得し、リンク時にリンカーが接続することです。これらは、bar.cppおよびbaz.cppで、foo.cppの実装に使用されます(これがリンカーの要点です)。

すべてをfoo.hに入れてこれを実行しようとすると、問題が発生します。 foo.hがdoFoo()という関数を宣言しているとします。この関数の定義(コード)がfoo.ccにある場合は、問題ありません。ただし、doFoo()のコードをfoo.hに移動し、foo.cpp、bar.cpp、baz.cpp内にfoo.hを含めると、doFoo()であり、同じスコープ内に同じ名前の物を複数持つことは許可されていないため、リンカーは文句を言います。

1
Tyler McHenry

ヘッダーファイルで#includeを使用しても問題はありません。これは非常に一般的な方法です。他に必要なあいまいなヘッダーを覚えておくことで、ユーザーにライブラリに負担をかけたくない場合があります。

標準的な例は#include <vector>。ベクトルクラスを取得します。また、ベクタークラスを適切にコンパイルするために必要な多数の内部CRTヘッダーファイルは、本当に必要ではなく、知りたくないものです。

1
Hans Passant

.cppファイルを#includeすると、リンカーから「複数の定義」エラーが大量に発生する可能性があります。理論的には、すべてを1つの翻訳単位に含めることができますが、1つのファイルに変更を加えるたびに、すべてを再構築する必要があることも意味します。実際のプロジェクトでは、それは受け入れられません。そのため、makeのようなリンカーやツールがあります。

1
anon

ヘッダーファイル内からヘッダーファイルをインクルードすることは問題ないため、c ++ファイルにインクルードすることもできますが、ビルド時間を最小限に抑えるために、特に多くのc ++ファイルに同じヘッダーが含まれる場合は特に必要でない限り、別のヘッダー内からヘッダーファイルをインクルードしないことが一般的に望ましいです。

1
Paul

「インクルードガード」を使用すると、複数の定義エラーを回避できます。

(begin myheader.h)
#ifndef _myheader_h_
#define _myheader_h_
struct blah {};
extern int whatsit;
#endif //_myheader_h_

これで、他のヘッダーファイルに「myheader.h」を#includeすると、(_ myheader_h_が定義されているため)一度だけインクルードされます。 MSVCには、同等の機能を備えた「#pragmaonce」があると思います。

0