More C++ Idioms/ハンドル・ボディ(Handle Body)

出典: フリー教科書『ウィキブックス(Wikibooks)』
移動先: 案内検索

ハンドル・ボディ(Handle Body)[編集]

意図[編集]

  • 実装からインターフェイスを分離する
  • 実装の詳細が変更されても、そのクラスの使用者に影響がないように(再コンパイルを不要に)する

別名[編集]

  • Bridge (Gamma et al.)
  • コンパイル防壁(Compilation Firewall)
  • チェシャ猫(Cheshire Cat)
  • PImpl (Pointer to Implementation) idiom

動機[編集]

C++ ではクラスは実装を定義するとともにインターフェイスを宣言することにも使われる。 プライベートメンバ関数は、クラスの「インターフェイス」ではないにもかかわらず、クラス利用者に見えるようにクラスの中で宣言しなくてはいけない。 プライベートデータメンバの宣言やプライベート関数のシグネチャを変更すると、利用者のコードも再コンパイルしなくてはいけなくなる。 したがって、クラスの実装からインターフェイスを分離し、不必要な再コンパイルを防ぐのは有用である。

解法とサンプルコード[編集]

abstractionを2つの実装クラスに分離する。 ひとつは識別子としての役割をし、利用者に対してクラスインターフェイスとなる。 これはハンドルと呼ばれる。 他方のクラスは、実装を具体化し、ボディと呼ばれる。 ハンドルはメンバ関数の実行をボディにフォワードする。

// String.hppファイル
class StringRep; // 前方宣言のみ

class String {
  public:
    String();
    String(const String &s);
    String &operator=(const String &s);
    ~String();
    String(const char *s);
    . . . .
  private:
      StringRep *rep; // ポインタで実装する (pimpl)
};
// String.hppファイル ここまで


// String.cppファイル
#include "String.hpp"

namespace { // 無名名前空間
  class StringRep {
    // このクラスの定義はクライアントからは見えないようにし、
    // Stringクラスとは別々のソースファイルとしてコンパイルされるべき。
    friend class String;

    StringRep(const char *s);
    ~StringRep();
    int count; char *rep;
  };
} // 無名名前空間終わり

String::String() // コンストラクタや、その他諸々の定義
. . . .

これにより、実装(ボディ)に対して安全にデータの変更を行うことができ、ハンドルの利用者は再コンパイルの必要がない。 実装はポインタの影に「より隠される」ので、コンパイルファイアウォールとも呼ばれる。

問題点[編集]

既知の利用[編集]

  • 単純でないC++ソフトウェアでは広く用いられている!

関連するイディオム[編集]

References[編集]

Copyright[編集]

Original copyright ©1998 Lucent Technologies, Bell Labs Innovations. All rights reserved. Permission granted to reprint verbatim for non-commercial use provided this copyright notice appears. (Contents edited for Wikibooks).