C++のコーディングガイドライン
C/C++の書き方についてはGoogleが作ったC++のスタイルガイドが参考になります。
よい書き方/よくない書き方の例に加え、メリット/デメリットなども書いてあるため、自分のアプリケーションで採用するかどうかの判断材料になります。
また、cpplintというリンターもあります。
注釈
cpplintはもともとGoogleが開発していたオープンソースプロジェクトでしたが、現在ではGoogleの手を離れたプロジェクトになっているようです。
インクルードガード
1#ifndef Geometry_h
2#define Geometry_h 1
3
4// ヘッダーファイルの内容
5
6#endif
インクルードガード(もしくは #define ガード)は、
同じヘッダーファイルが複数回インクルードされるのを防ぐために
ファイルの先頭に#ifndefを使ってチェックする書き方です。
Geant4のヘッダーファイルはすべてガードが定義されています。 自分が作るコードも同じようにガードするとよいです。
注釈
#ifndefを使う伝統的な書き方の代わりに、#pragma onceという書き方も広く使われています。
1行で書けて分かりやすい反面、C++の標準規格には含まれていない拡張機能です。
Googleスタイルガイドでは伝統的な書き方が推奨されていますが、
このドキュメント内のサンプルコードでは#pragma onceを使っている箇所もあります。
前方宣言
1// #include "G4Event.hh"
2// インクルードする代わりに前方宣言する
3class G4Event;
4
5class EventAction : public G4UserEventAction
6{
7 public:
8 void BeginOfEventAction(G4Event* aEvent);
9 void EndOfEventAction(G4Event* aEvent);
10 // 引数はG4Eventへのポインタ型なので
11 // クラスの完全な定義がなくても
12 // 前方宣言だけでコンパイルできる。
13};
ヘッダーファイルをインクルードする代わりにclass クラス名;と書くことを前方宣言と呼びます。
「こういう名前のクラスがあるよ」ということをあらかじめお知らせすることで、コンパイルエラーを避けることができます。
注釈
前方宣言だけでコンパイルできるのは、
そのクラスをポインタ(G4Event*)や参照(G4Event&)として使う場合に限られます。
値そのものをメンバー変数として持ったり、
そのクラスのメソッドを呼び出したりする場合は、
クラスの完全な定義(=#include)が必要です。
また、ヘッダーで前方宣言していても、
実装ファイル(.cc)側でそのクラスのメソッドを呼び出す場合は、
結局そちらで#includeする必要があります。
前方宣言はあくまで「ヘッダーファイル側のコンパイルを軽くする」ための工夫です。
Geant4では多用されていますが、Googleスタイリングガイドでは、できるかぎり使わないことが推奨されています。 なので、僕はあまり使わないようにしています。
注釈
前方宣言を避けたほうがよいとされる理由は、
依存関係が見えにくくなったり(#includeならヘッダーを見ただけで依存先が分かる)、
値渡しやメンバー変数に変更したときにコンパイルエラーの原因が分かりにくくなったりするためです。
一方で、循環参照を避けたい場合や、 Geant4本体のような大規模フレームワークでコンパイル時間を短縮したい場合には、 前方宣言が積極的に使われています。
「理由がなければ#include、理由があれば前方宣言」くらいの判断軸で考えるとよさそうです。