一応理屈の説明を
"#"で始まる命令はプリプロセッサ命令と言って、コンパイルの前のタイミングにプリプロセッサによって処理される物です(プリプロセス処理と言います)。
どこかの.cppファイルの内部で[#include"hoge.h"]と書かれていれば、プリプロセッサはhoge.hを頭から読んで行きます。
#ifndef HOGE_H
#ifndefは、その後に続くトークンが定義されていなければ、#ifndef以降#endifまで(あるいは#elseまで)のテキストをコンパイルに含めます。トークンの定義というのは#defineで行います。この場合、"HOGE_H"はまだ定義されていないので、#ifndef以降のテキストが読み込まれます。
#define HOGE_H
#ifndefの直後に"HOGE_H"が定義されます。
#endif
ここまで読んで終わり
さて、別の.cppファイルがやはり[#include"hoge.h"]と書いてあれば、プリプロセッサは馬鹿正直に同じファイルを読みに行きます。しかし、今度は"HOGE_H"が定義されているので、#ifndef内はスルーされます。これによって、ヘッダファイルが重複してインクルードされるのを防ぎます。これが「インクルードガード」です。
インクルードガードの必要性
なぜ重複インクルードされると困るのかといいますと、コンパイルエラーになるからです(笑)。理由を以下に説明します
#includeが行う処理は(わかりやすく言えば)テキストファイル(この場合は.cpp)の中に別のテキストファイル(この場合はhoge.h)を単純にコピー&ペーストするだけなのです。これにより、以下のような3つのヘッダファイルを作ったときに問題が発生します。
classA.h
class classA{ ... };
classB.h
#include "classA.h" class classB{ ... };
classC.h
#include "classA.h" #include "classB.h" class classC{ ... };
この時、classC.hは、実際には以下のように展開されてしまいます
class classA{ ... }; class classA{ //classB.hでインクルードされた//classC.hでインクルードされた ... }; class classB{ //classC.hでインクルードされた ... }; class classC{ ... };
みてわかるとおり、classAが2回宣言されてしまいます。これは「すでに定義されているクラスが再定義されました」という旨のコンパイルエラーを吐き出します。