同じクラスの再定義を防止する - C++ プログラミング

PROGRAM


同じクラスの再定義を防止する

C++ では、特に何も配慮していないと、同じヘッダーファイルを 2 回インクルードしたときに、定義が重複しているとしてエラーになってしまいます。

具体的には、Visual Studio 2012 の場合は "'class' 型の再定義" とか、Xcode 4.5.2 では "Redefinition of 'Class'" といったエラーになります。

同じヘッダーファイルを 2 回インクルードする場面は、単純に同じヘッダーファイルを同じファイル内で 2 回 #include した場合だけでなく、あるヘッダーファイル A を B がインクルードして、それを C がインクルードしているときに、あるファイルで C と A をインクルードした場合にも発生します。

#pragma once で回避する方法

このような二重インクルードを避けるためには、ヘッダーファイルのどこかに #pragma once ディレクティブを記載します。

#pragma once

 

class MyClass

{

}

こうすることで、このヘッダーがインクルードされた後、再びインクルードされようとしても読み込まないようにしてくれます。

#pragma once を記載する位置は、Visual Studio 2012 でも Xcode 4.5.2 でも、どこに書いても期待通りに動いてくれるようでしたけど、ヘッダーファイルの冒頭あたりに記載するのが自然なように思います。

 

ただし、この #pragma once ディレクティブを使う方法はコンパイラに依存する書き方なので、採用しているコンパイラは多いものの、コンパイラによっては期待通りに動かない可能性も全くないとは言えないようです。

それでも、Visual Studio とか GCC とか Xcode とか、主要な環境ではしっかりサポートされているので、特殊なコンパイラや不特定相手を狙うのでなければ、積極的に使って行っても問題ないと思います。

 

#define で回避する方法

二重インクルードを避けるもう一つの手段として、#define ディレクティブを使ったマクロ定義を応用する方法があります。

#ifndef MyProject_Header_CMyClass

#define MyProject_Header_CMyClass

 

// #ifndef から #endif までの間に定義を記載します。

class MyClass

{

}

 

#endif

#define で二重インクルードを防止するにあたり、まず、絶対重複しないと考えられるマクロ名を決めます。

ここでは、そのマクロ名として "MyProject_Header_CMyClass" を使うことに決めたら、まずはそれが定義されていないかを #ifndef ディレクティブで判定します。

ちなみに #ifndef ディレクティブというのは、指定されたマクロが定義されていなかった場合に "真" になります。

 

マクロが定義されていない場合に限り、#endif までのブロックが処理されるので、その中で #define ディレクティブを使って判定に使ったマクロ名を定義してあげます。

そうすることで、このヘッダーが再びインクルードされたとしても、次は #ifndef が定義済みと判断されるため、次からはブロックの中の定義を読み込まないでくれます。

 

この #define や #ifndef といったディレクティブは C++ の仕様で動作が定められたものなので、これを使えばほぼ確実に二重インクルードを防止することができます。

ただ、今となっては主要な環境では #pragma once を使うことができるので、#define を使わなければいけない理由が無ければ、#pragma once を使った方が、簡単で確実なのかもしれません。


[ もどる ]