前方宣言とインクルード


17

Reduce the number of #include files in header files. It will reduce build times. Instead, put include files in source code files and use forward declarations in header files.

これをここで読みます。http://www.yolinux.com/TUTORIALS/LinuxTutorialC++CodingStyle.html

そのため、ヘッダーファイル内のクラス(クラスA)が、あるクラス(クラスB)の実際の定義を使用する必要がない場合に表示されます。そのとき、特定の(クラスB)ヘッダーファイルを含める代わりに、前方宣言を使用できます。

質問:ヘッダー内のクラス(クラスA)が特定のクラス(クラスB)の実際の定義を使用しない場合、どのように前方宣言がコンパイル時間の短縮に役立ちますか?

回答:


11

コンパイラは、クラスAがクラスBを使用するかどうかを気にしません。クラスAがコンパイルされ、クラスBの事前宣言(前方宣言など)がない場合、パニックしてエラーとしてマークすることのみを認識します。

ここで重要なことは、猫がキーボードを歩いてクラスとして解釈される場合とされない場合があるランダムな文字を作成した後、プログラムをコンパイルしようとしていないことをコンパイラが認識することです。

含まれている情報を使用できるように、インクルードを検出した場合、ファイルを開いて解析する必要があります(実際に必要かどうかに関係なく)。そのファイルに他のファイルが含まれている場合は、それらも開いて解析する必要があります。これを回避できる場合は、代わりに前方宣言を使用することをお勧めします。

編集このルールの例外はプリコンパイル済みヘッダーです。この場合、すべてのヘッダーはコンパイルされ、将来のコンパイルのために保存されます。ヘッダーが変更されない場合、コンパイラーは以前のコンパイルからプリコンパイルされたヘッダーをスマートに使用できるため、コンパイル時間を短縮できますが、ヘッダーを頻繁に変更する必要がない場合にのみ有効です。


ご説明ありがとうございます。[OK]を例として、次の3つのヘッダファイルがあると思いvehicle.hbus.htoybus.hvehicle.hinclude by bus.hおよびbus.hinclude by toybus.h。ので、私はいくつかの変更を行う場合bus.h。コンパイラはvehicle.h再び開いて解析 しますか?再度コンパイルしますか?
ナヤナアダスリヤ

1
@NayanaAdassuriyaはい、毎回インクルードおよび解析されます。これは、ヘッダーファイルで宣言を表示#pragma onceまたは#ifndef __VEHICLE_H_入力して、そのようなファイルが複数回インクルードされるのを防ぐためです(少なくともifndefの場合は複数回使用されます)。
ニール

4

A.hppは#include B.hppを必要としないため

A.hppは

class B;//or however forward decl works for classes

class A
{
    B* bInstance_;
//...
}

A.hppが含まれている場合、B.hppは暗黙的に含まれず、A.hppのみに依存するすべてのファイルは、b.hppが変更されるたびに再コンパイルする必要はありません。


ただし、ソースファイル(A.cpp)では。実際のヘッダーファイル(Bh)を含める必要があります。そのため、コンパイルする必要があるたびに。最後に、Bhは変更を加えて再コンパイルする必要があります。違う?
ナヤナアダスリヤ

@NayanaAdassuriyaいいえ、AはBへのポインターのみを使用し、Bへの変更はA.hpp(またはそれを含むファイル)に影響しないため
ラチェットフリーク

@NayanaAdassuriya:はい、A.cppは再コンパイルする必要があります(Aのメソッドのボディ内でBの定義を使用する場合、通常は使用します)が、Aを使用し、Bを直接使用しないC.cppは再コンパイルしません。
Jan Hudec

3

C / C ++プリプロセッサは、別個の純粋にテキストの処理ステップであることに注意してください。#include含まれるヘッダの内容に指令引き、コンパイラがそれを解析しなければなりません。さらに、それぞれのコンパイル.cppは完全に分離されているため、B.hコンパイル時にコンパイラーが解析しただけでは、コンパイルB.cpp時に再度必要になる場合はあまり役に立ちませんA.cpp。そして再びコンパイルするときC.cpp。そしてD.cpp。等々。また、含まれているファイルが変更された場合は、それらの各ファイルを再コンパイルする必要があります。

だから、クラスAはクラスBとクラスCD使用し、クラスを使用すると言いAますが、操作する必要はありませんB。クラスAがの前方宣言だけで宣言できる場合BB.h2回コンパイルされます:コンパイル時B.cppA.cpp(メソッドのB内部でまだ必要なためA)。

ときでもA.h含まれB.h、それがコンパイルされた4回のコンパイルをB.cppA.cppC.cppD.cpp後の2は今、間接的に含まれてB.hあまりにも。

また、ヘッダーが複数回含まれている場合でも、プリプロセッサはそれを毎回読み取る必要があります。ガード#ifdefsのためにコンテンツの処理をスキップしますが、それを読み取り、ガードの終わりを検索する必要があります。つまり、内部のすべてのプリプロセッサディレクティブを解析する必要があります。

(他の回答で述べたように、プリコンパイル済みヘッダーはこれを回避しようとしますが、それらは独自のワームの缶です。基本的には、それらをあまりにも多く使用していない場合にのみシステムヘッダーに合理的に使用できますが、プロジェクトのヘッダー)


+1、ヘッダーインクルードは、クラスAとBが2つしかない場合ではなく、かなり多数のクラスがある場合にのみ深刻な問題になります。他のすべての投稿は、その中心点を見逃しているようです。
Doc Brown

2

前方宣言は、それ自体がさらに多くのヘッダーファイルを含むヘッダーファイル全体よりも解析がはるかに高速です。

また、クラスBのヘッダーファイルで何かを変更した場合、そのヘッダーを含むすべてを再コンパイルする必要があります。前方宣言では、それはAの実装が常駐するソースファイルのみである可能性があります。しかし、Aのヘッダーが実際にBのヘッダーを含んa.hppでいた場合、Bを使用しなくても、すべてを再コンパイルします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.