oF (C++)でクラス二重定義してるぞと言われないために

openFrameworksをガリガリ書いているんですが,

C++でクラスをファイル分けして書いていると,ヘッダファイルを二重インクルードしてしまいビルドが通らないなんてことがあります.

具体的に書くと

  • A.h: class hoge{}
  • B.h: #include A.h
  • C.h: #include A.h , #include B.h

こんな状態.C.hにはA.hが二度インクルードされちゃって,hogeクラスが二重定義になっているのでこのままだとエラーが出ます.

この様なエラーを解決する方法が二つあるのでそれに関して書きます.

#ifndef#define#endif

Xcode ver.5.1.1 で新しくC++ファイルを作成すると,一緒にヘッダファイルも作成されるんですが,デフォルトだと中身がこんな感じになってます.(例えばtestClass.hだと)

#ifndef __testClass__testClass__
#define __testClass__testClass__

#include <iostream>
  //ここにクラス定義等を記述

#endif /* defined(__testClass__testClass__) */

この中の#ifndef#define#endifがその二重インクルードによる二重定義を解決してくれます.

どう解決してくれるかというと,これらはC++のソースをコンパイルする前にソースに前処理をする「プリプロセッサ」に関するの記述で,

  • もし#define hogeされていたら,
  • #ifndef hoge~#endif hoge内はスキップする

という処理をしてくれます. この記述方法をインクルードガードと呼ぶそうです.便利ですね.

ただしこれより簡単な記述で同じような処理をしてくれるものがあります.

#pragma once

それが#pragma onceというコマンド(?と呼べば良いのか)です.

openFrameworks ver.0.8.1 に含まれているprojectGenerator.appで「testProject」というプロジェクトを作成すると,srcフォルダの中に

  • main.cpp
  • ofApp.cpp
  • ofApp.h

というファイルが作成されるんですが,ofApp.hの中身を覗いてみると,

#pragma once

#include "ofMain.h"

class ofApp : public ofBaseApp{
  ...

というように,ファイルの冒頭に#pragma onceという記述があります.

この記述がインクルードガードと同じ働きをしするんですね.もし二重にインクルードされた場合には呼び出しを無視して中身をスキップしてくれます.便利です.

技術書とかリファレンス読むの大事だな

#pragma onceは新しいコンパイラでないと対応していないため,上記二つを併記するという裏技も存在するようです.

最新バージョンのXcodeとopenFrameworksを使っているなら気にしなくても良いですね.

どの言語に関しても言えることですが,知らない人が書いたブログ上のコードをコピペして勉強するだけじゃ気づかないこと知らないまま過ごしてしまうことが多いので,本を呼んで順序よく体系立てて学ぶのは時間かかる反面理解が深まるし深く定着するので良いです.