C++ プログラミングガイド

ヘッダーファイル

効率的なヘッダーファイルを作成するのは困難な場合があります。通常ヘッダーファイルは、C と C++ 両方のさまざまなバージョンに適応させなければなりません。テンプレートを用意する場合は、2 度以上のインクルードが可能 (べき等) で、他のファイルを必要としないものにしてください。

言語に対する適合性のあるヘッダーファイル

ヘッダーファイルは、C と C++ プログラムの両方にインクルードできるようにしなければならない場合があります。しかし、従来型の C としても知られる「Kernighan and Ritchie C」(K&R C)、ANSI C (日本語版は 『注解 C++ リファレンスマニュアル』) の C++ (ARM C++)、および ISO C++ は、1 つのヘッダーファイル内の同じプログラム要素に対して異なる宣言や定義を規定している場合があります (言語およびバージョンによる違いの詳細は『C++ 移行ガイド』を参照)。これらの標準のすべてに受け入れられるようにヘッダーファイルを設定するには、プリプロセッサマクロの __STDC____cplusplus が存在するかどうか、また、存在する場合はその値が何であるかに応じて、条件付きコンパイルを使用しなければならない場合があります。

マクロ __STDC__ は、K&R C では定義されていませんが、ANSI C と C++ では定義されています。このマクロは、K&R C コードを ANSI C または C++ のコードと分ける際に使用してください。このマクロは、プロトタイプ宣言された関数定義とプロトタイプ宣言されていない関数定義を分けるのに最も便利です。


#ifdef _ _STDC_ _
int function(char*,...);     // C++ および ANSI C の宣言
#else
int function();              // K&R C
#endif 

マクロ __cplusplus は C では定義されていませんが、C++ では定義されています。


注 -

C++ の初期のバージョンでは、マクロ __cplusplus ではなく c_plusplus が定義されていました。マクロ c_plusplus は、現在は定義されていません。


__cplusplus の定義は、C と C++ を分ける際に使用してください。このマクロは、次の例に示すように関数宣言に対する extern "C" インタフェースの指定を保護するのに最適です。extern "C" の指定の矛盾を防ぐため、extern "C" リンケージ指定のスコープ内には #include 指令を入れないでください。


#include“header.h”
                               //... 他のインクルードファイル ...
#if defined(_ _cplusplus
extern“C”{
#endif
  int g1();
  int g2();
  int g3()
#if defined(_ _cplusplus)
}
#endif

ARM C++ では、__cplusplus マクロの値は 1 です。ISO C++ では、このマクロの値は 199711L (この規格が制定された年月 long 定数として表現したもの) です。このマクロの値は、ARM C++ を ISO C++ と分ける際に使用してください。このマクロの値は、テンプレート構文内の変更を保護するのに最適です。


// テンプレート関数の特殊化
#if _ _cplusplus < 199711L
int power(int,int);                       // ARM C++
#else
template <> int power(int,int);         // ISO C++
#endif

べき等なヘッダーファイル

ヘッダーファイルはべき等でなければなりません。つまり、ヘッダーファイルを何度インクルードしても、その効果は 1 度だけインクルードする場合と同じでなければなりません。この特性は、テンプレートを作成する場合に特に重要です。ヘッダーファイルをべき等にするには、ヘッダーファイルの本体が 2 度以上出現することを防ぐプリプロセッサ条件を設定すると最も効果的です。


#ifndef HEADER_H
#define HEADER_H
/* ヘッダーファイルの内容 */
#endif

自己完結するヘッダーファイル

ヘッダーファイルには、完全なコンパイルに必要な定義がすべて含まれている必要があります。ヘッダーファイルは、必要な定義を含むヘッダーファイルをすべてその中にインクルードし、「自己完結」である、つまり他のファイルを必要としないように設定してください。


#include“another.h”
/* another.h に依存する定義 */

通常、ヘッダーファイルは、べき等であるとともに自己完結でなければなりません。


#ifndef HEADER_H
#define HEADER_H
#include“another.h”
/* another.h に依存する定義 */
#endif

不要なヘッダーファイルのインクルード

C++ で書かれたプログラムでは通常 C プログラムよりも宣言の数が多く、そのためコンパイル時間が C プログラムよりも長くなります。宣言の数は、いくつかの手法を使用することにより減らせます。

手法の 1 つは、ヘッダーファイルをべき等にするように定義されたマクロを使用して、ヘッダーファイル自体を条件付きでインクルードするものです。ただしこの手法は、ファイル間の依存を増やします。


#ifndef HEADER_H
#include“header.h”
#endif


注 -

システムヘッダーファイルには、_Xxxx (X は大文字) という書式の識別子が含まれていることがよくあります。これらの識別子は予約されているため、保護のためのマクロでは、この書式の識別子は使用しないでください。


コンパイル時間を減らす別の方法として、定義を含むヘッダーファイルをインクルードせずに、不完全なクラスと構造体 (struct) 宣言またはクラス (class) 宣言を使用できます。この手法は、完全な定義が不要で、識別子が typedef でも template でもなく、class または struct である場合に使用できます (標準ライブラリは、クラスではなくテンプレートである typedef を多数含む)。たとえば、次のように記述する代わりに、


#include“class.h”
a_class* a_ptr;

次のように記述します。


class a_class;
a_class* a_ptr;

(a_class が実際に typedef である場合、この手法は無効です)

もう 1 つの方法として、Erich Gamma 著の『オブジェクト指向における再利用のためのデザインパターン』 (ソフトバンク) に述べられているように、インタフェースクラスとファクトリを使用することもできます。