C++において、余計なinlucdeを減らすためにクラスの前方宣言を利用することは、基本的なテクニックだと思います。ただ、何もないシンプルなクラスの前方宣言ならまだしも、実際には名前空間があったり、templateだったりするクラスも普通に存在します。そのたびに、前方宣言の書き方を確認するのは無駄な時間なので、まとめておきます。
以下は、前方前言を記述するクラスのヘッダファイルのみを示します
(定義部分等はなくても大体予想がつくと思うので、あくまでも前方宣言にフォーカスします)。
普通の前方宣言
ごく一般的な前方宣言です。
class classB;
class classA
{
public:
classA();
~classA();
private:
classB *objB;
};
名前空間がある場合の前方宣言
メンバ変数にしたいクラスが名前空間で囲まれていたら、下記のようにします。
namespace NS_C{
class classC;
}
class classA
{
public:
classA();
~classA();
private:
NS_C::classC *objC;
};
typedefされているクラスの前方宣言
メンバ変数にしたいクラスがtypdefされている場合は、同じようにtypdefしてあげます。
class classD;
typedef classD classDD;
class classA
{
public:
classA();
~classA();
private:
classDD *objD;
};
usingされている場合の前方宣言
C++11以降では、積極的にusingが使われるようになると思いますが、そのような場合もtypdefと同じように、usingを書いてあげます。
class classE;
using classEE = classE;
class classA
{
public:
classA();
~classA();
private:
classEE *objE;
};
テンプレートクラスの前方宣言
テンプレートクラスの場合は下記のように書きますが、typedefもusingもテンプレートも結局、メンバ変数にしたいクラスの記述と同じよう記述をすれば大丈夫です。
template<typename T>
class classF;
class classA
{
public:
classA();
~classA();
private:
classF<int> *objF;
};
ごちゃごちゃしたクラスの前方宣言
いろんな要素が入っていてごちゃごちゃしているクラスも、ちゃんと構造を理解して同じように書いてあげれば大丈夫です。
namespace NS_G{
template<typename T>
class classG;
typedef classG<int> classGG;
using classGGG = classGG;
}
class classA
{
public:
classA();
~classA();
private:
NS_G::classGGG *objG;
};
注意:インナークラスは前方宣言できない
インナークラスの場合は、前方宣言できません。とっとと諦めて、設計を見直しましょう。
class classH;
class classH::classHinner; // NG! 認識できない型(classH)が利用されています
class classA
{
public:
classA();
~classA();
private:
classH::classHinner *objH; // NG!
};
上記ソース全ソースはGithubに上げています(いらないと思いますけど・・・)。
メンバにクラスポインタをもたせると、メモリ管理がめんどくさい・・・いやいや、スマートポインタ使いましょう。
以上、他にもこんな前方宣言があるよって方はご教示ください。