ヘッダファイルをインクルードする理由

 ヘッダファイルとはなんの為にあるのでしょうか? 何故.cppファイルからインクルードしなければならないのでしょうか? その為には、C++言語において、ソースコードがどのようにコンパイルされるかを把握する必要があります。

話がずれますが、.hのファイルは「ヘッダーファイル」と言うのですが.cppのファイルは用語がありません^^;。一般的には「ソースコードファイル」と呼ぶようですが、じゃあヘッダーファイルはソースコードファイルじゃないのかよって話が^^;

 【今からする話は、コンパイラやリンカが行う作業を極めて単純化した物です。みはえる自身が良くわかってないので適当に書いてます。もしよろしければご指摘or参考URLをいただければ幸いです】

 C++では「分割コンパイル」という方法が採用されています。これは、個々のソースファイル(ここでは.cppファイルを差す)を一つずつコンパイルしてオブジェクトファイルを作成し、その後、オブジェクトファイルを結合して実行形式ファイルを出力するという方法です。

 まず、コンパイラがビルド命令を受けると、プリプロセッサによってプリプロセス処理を実行します。まず、.cppファイルが一つ読み込まれ、頭から全部読み始めます。この時、"#"で始まる文があった場合、プリプロセッサ命令とみなされ実行されます。プリプロセッサ命令では"#ifdef"など分岐構文がありますから、この時点で(分岐から外れた為に)読み込まれ無かったファイルも当然あります。

 プリプロセス処理が終わると、その.cppファイルは、オブジェクトファイル(.oあるいは.obj)という中間言語に変換されます。すべての.cppファイルが.objファイルに変換されたら、これらを全て連結し、コンパイルを行います。この時、複数の.objファイルで同名のクラス「定義」が存在する場合、再定義エラーが発生します。

 さて、今からとても重要な話をします。

 C++では、あらかじめ宣言されていないクラスを利用する事ができません。

 「あらかじめ」というのは、利用したいクラスを実行する瞬間より前の事です。何故か? 理由はいくつかありますが「なるべくコンパイル時エラーで問題を処理する」事と「サイズがわからないと実装できない」というのが大きいです。

struc Hoge{
int a;
int b;
} hoge;

 この構造体に対して"hoge.c = 4;"とか存在しないメンバにアクセスする誤ったコードを書いた際に、「そんなメンバはありません」とコンパイルエラーを出すのが一つ。

もう一つは

class A{
int moge;
Hoge hoge;
} a;

 このようなクラス宣言を作った場合、Hogeのサイズが必要になります。サイズがわからないとAを作成できないからです。(←もうちっと詳しい説明が必要なのですが、サイズ確定がどのタイミングで起きるのかわからないので、いったんここでおいておきます)

 以上の理由により、C++ではあらかじめ宣言されていないクラスを利用する事が出来ません。

 さあ、ここまで来て気づいた方もいらっしゃる事でしょう。そうです。コンパイルの段階では.cppは1ファイルずつコンパイルされます。もし、ある.cppファイルが別の.cppファイルで定義されたクラスを用いている場合、そのクラスの構造を知る事が出来ないのです!

 その為に、#includeがあるわけです。

面白いのは、クラスの構造とインターフェイスさえ取得できれば、実装は無くてもコンパイルは出来るのです。ですからヘッダファイルだけインクルードすれば良いわけですね。