C++ファイル分割
またまた久しぶりにC++を書こうとすると,ヘッダファイル,ファイル分割を忘れてしまっていたので,整理.
全般
- 共通にするものをヘッダに書く(当たり前だけど).
- 宣言と定義の違いを持つこと.宣言は名前だけ.定義は実態を生成する文.
- 定義は(普通)は一つ.ということで関数の定義や,変数の定義は書かない.
- 逆に変数の宣言(extern)はヘッダに書く.共通したいから.
- グローバル変数は実態を(何処か1つの)ソースファイルに書いて,そのヘッダにexternで宣言する.他のソースをはそのヘッダをインクルードする.
- static変数は(普通は)ヘッダに書かない.ヘッダに書くってことはそのヘッダをインクルードしたソース(Cのインクルードは基本的にコピー)全てに,ソース固有のstatic変数が生成される.
- ヘッダの中で不要にヘッダファイルをインクルードしない.相互依存が発生してしまうし,そのヘッダをインクルードしているソース全部が再コンパイルされてしまう.ラベルが欲しいだけなら前方宣言を利用する.
前方宣言
- クラス定義をしていると,他のクラスを変数として持ちたいことが(当然だけど)ある.その場合にそのクラスのヘッダファイルをインクルードしないといけなくなって,すぐにヘッダの依存関係が混雑してしまう.
- そんな時に利用するのが,その変数をポインタとして持つ方法.ポインタであればメソッドやメンバ変数などの情報(というかコンパイル時のメモリ割当)が不要(ポインタ64ビットか32ビットあれば良い)だから,ラベルさえあれば良い.
// シンプルVer. class Hoge; // <- 前方宣言 class Foo { private Hoge *hoge; // <- ポインタで持つ }; // 名前空間の下にいるVer. namespace BAR { class Hoge; } class Foo { private BAR::Hoge *hoge; };
extern C {...}
- Cの関数をC++でも使えるようにするための宣言.
- 関数名はコンパイル時にリネームされる.しかし,その方法がCとC++で異なるため,普通にコンパイルするとリンクエラー(そんな名前の関数無いよ)になる.
- それを避けるために,extern C {...}で囲っておく.特に,g++とかだと_cplusplusマクロが定義されているから,それでifdefする.
#ifdef _cpuluspulus extern C { #endif ... // Cの宣言文 #ifdef _cpuluspulus } #endif