一応理屈の説明を

"#"で始まる命令はプリプロセッサ命令と言って、コンパイルの前のタイミングにプリプロセッサによって処理される物です(プリプロセス処理と言います)。

どこかの.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内はスルーされます。これによって、ヘッダファイルが重複してインクルードされるのを防ぎます。これが「インクルードガード」です。