pimplイディオム

実装をヘッダファイルに書かないためにそのすべてのメンバを実装したクラスへのポインタのみをメンバにもつことをpimpl*1イディオムと呼ぶ。

2/24 パターン→イディオム


たとえば、以下のようなクラス定義がある。

#include "Mystring.h"

class Hoge{
public:
        Hoge();
        ~Hoge();
	void func(int x);
private:
	MyString str_;
};

このとき、クラスHogeはprivateなメンバstr_の型MyString?に依存している。
依存しているとは、MyString?の宣言が変わればクラスHogeも変わったことになってしまうこと。このため、上記宣言を参照している部分はすべて再コンパイルの必要がでてくる。しかし上記の宣言ではstr_に対し何の操作もしていないことから、pimplイディオムの用いて依存性の解消を試みることができる。
pimplイディオムでは上記の宣言は以下のようになる。

//MyStringに対するヘッダいらない
//#include "Mystring.h"
class Hoge_imp;//実装クラスの前宣言
   
class Hoge{
public:
        Hoge();
        ~Hoge();
 	void func(int x);
private:
 	Hoge_imp *pimp_;//ポインタであること。
};

そして実装ファイルには以下のように記述する。

#include "MyString.h"//ヘッダに書かずにこちらに書く
//--------------
//Hoge_imp
//--------------
//実装クラスの実際の宣言・定義
class Hoge_imp{
public:
  	void func(int x);
private:
	MyString str_;
};   
Hoge_imp::func(int x){
//何か実装
}  
//--------------
//Hoge
//--------------
Hoge::Hoge(){
	pimp_ = new Hoge_imp();//実装クラスの生成
}  
Hoge::~Hoge(){
	delete pimp_;//作ったら消す。
}  
Hoge::func(int x){
	pimp_->func(x);//丸投げ
}

Pimplイディオムはメンバを2回書かなくてはいけないため、面倒が増えてしまうという弱点が存在するが、

  1. 依存関係を減らすことができる。
  2. 名前空間の汚染を防ぐことができる。

という2点の特徴があるため、

  • メンバとして複数の型を使用しているクラス
  • C言語で書かれたレガシーなコードを利用するとき

などに効果的である。(特に後者の用法では必須と言ってもいいかもしれない)

*1:Pointer of IMPLement