Entry

プログラミングメモ - pimpl パターンとローカル実装の比較の話とか

2009年11月07日

こちらの話を読んでいて。コードが長いので,詳細はリンク先を参照してください。

ここで質問です。よりシンプルに、かつ速度的にも有利に見える後者ではなく、pimplパターンを使うメリットは何なのでしょうか?

VirtualとpImplの速度について -OKWave

まとめて言うと,pimpl パターンを使うことと,純粋仮想関数を宣言した基底クラスだけを晒して,仮想関数を実装した派生クラスを翻訳単位から隠すことは,どう違うんだという話(まとまってるか?)。サンプルのコードはトップレベルに生成関数があるけれど,これは基底クラスの中に入れちゃえばいい話なので(下記参照),あまり問題ではありません。

class VirtualBase {
public:
    virtual void Func() = 0;
public:
    static VirtualBase* CreateVirtualBase();
};

おそらくこれは,pimpl パターンとのメリットを比較する以前の問題として,こういう継承関係を作ることがそもそも,あまりよろしくないんじゃないだろうか。どゆことかというと,CreateVirtualBase() 関数の実装は,

VirtualBase* VirtualBase::CreateVirtualBase() {
    return new VirtualDeri;
}

こうなってるわけだけれども,基底クラスが派生クラスの存在を予定している(派生クラスに依存している)ことになってしまってます。主従の関係が保ててない。基底クラスは実装済みの派生クラスを知ってちゃいけない建前からすると,ちと奇妙な実装です。

でも,ここでの話は,DLL にまとめる際にヘッダからメンバ変数を隠蔽したいってなことですから,実害がなけりゃ抜け穴的な使い方として使ってもいいじゃね?ともなりそうですよね(あたしは嫌だけれども),これ,どんなときに困るんだろう。

例えば,ライブラリのユーザが,VirtualBase クラスを拡張して別の派生クラスを作るとします。この場合,ユーザからは VirtualBase クラスの宣言しか見えないので,VirtualDeri クラスを派生させたクラスが作れません。単純に VirtualBase のインターフェイスを継承した新しいクラスしか定義できなくなってしまう,と。一方,pimpl の場合は,継承関係で隠蔽するわけじゃないので,pimpl の実体を持った派生クラスを作ることができます(pimpl パターンは private メンバを詰め込むもんだから,そもそも派生クラスが pimpl の存在を意識する必要はない)。

また,引用の回答にもある通り,実装を交換できるかという点でも違いはあるんだと思います。しかし,インターフェイスを固定して,異なるオブジェクトに動的にディスパッチしたいだけなら,Command パターンを利用すればいいし,これなら実装を翻訳単位から隠すこともできます。んなもんで,わざわざ pimpl の機構を使うメリットはなさげです。

ここで,継承関係を正常に保ちつつ,しかも生成する派生クラスの名前を隠蔽したまま,目的のオブジェクトを作る,という話になると,いきなり問題が難しくなります。こゆとこまでくると,実装の隠蔽云々というよりは,汎用プログラミングのドロドロ世界に突入してしまうんでしょうけど。

pimpl の速度が問題だったら,『Exceptional C++』の「高速 pimpl」を試してみるのもいいのかもしれない。

Exceptional C++―47のクイズ形式によるプログラム問題と解法 (C++ in‐Depth Series)
ハーブ サッター 浜田 光之
ピアソンエデュケーション
売り上げランキング: 124795
おすすめ度の平均: 4.5
5 C++の森に分け入るには
4 Koeingの名前空間照合規則を理解させてくれた本
5 C++における例外処理の啓蒙書
5 C++ユーザー必読デス。
4 実はC++の批判本

とはいいつつも,pimpl の使い道ってあたしもまだモヤモヤなんですけどね。。

Trackback
Trackback URL:
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN