pimpl イディオムで使用されている実装クラスにプライベート メンバーを持たせる理由はありますか? 私が本当に考えることができる唯一の理由は、自分自身から身を守ることです。つまり、プライベート メンバーは、クラスとユーザーの間である種の契約を強制する役割を果たします。この場合、クラスとユーザーはかなり密接に関連しているため、必要ないようです。
7 に答える
Pimpl の慣用句を Adapter/Bridge/Strategyのパターンと混同していると思います。イディオムは言語固有のものです。パターンは多くの言語に適用できます。
Pimpl イディオムは、C++ の次の問題に対処するために考案されました: クラスのプライベート メンバーがクラス宣言で表示され、不要な #include 依存関係がクラスのユーザーに追加されます。このイディオムは、コンパイラ ファイアウォールとも呼ばれます。
実装が外部クラスの対応する *.cpp ファイルに直接記述されていて、モジュールの外部からアクセスできない場合は、単純に Pimpl クラスの構造体を使用してもまったく問題ないと思います。実装が直接再利用されることを意図していないという考えをさらに強化するために、実装をプライベートな内部構造体として定義します。
// foo.h
class Foo : boost::noncopyable
{
public:
...
private:
struct Impl;
boost::scoped_ptr<Impl> impl_;
};
// foo.cpp
struct Foo::Impl
{
// Impl method and member definitions
};
// Foo method definitions
実装クラスのヘッダー ファイルができたら、もう Pimpl のイディオムについて話している必要はないと思います。むしろ、アダプター、ブリッジ、戦略、インターフェースクラスなどについて話しています...
ちょうど私の2セント。
pImpl の実装に依存します-具体的にはクラス不変を適用する場所ですが、一般に、impl 部分に保護/プライベート メンバーを含める必要はないと思います。実際、通常は構造体として宣言します。
理論的には、pimpl クラスは他のクラスと同じです。インターフェイスの具体的な実装であるということは、他のコードが pimpl クラス自体のクライアントではないという意味ではありません。
そうは言っても、実際には、pimpl クラスは本格的なオブジェクトではなく、いくつかのメンバー関数を持つ構造体に近い傾向があり、インターフェイスを実装から分離する必要性が少ないことがわかりました。
プライベートメンバーを持たないのはなぜですか?1 つのインターフェイスを PIMPL として定義しているからといって、それ以外のときにそのクラスを使用したくないというわけではありません。
まだまだクラスです。データはおそらく非公開または保護されているはずです。パブリック、プライベート、または保護されたユーザーが決してアクセスできないデータに対する操作。公開、保護、または公開したい操作。
私が本当に考えることができる唯一の理由は、自分から自分を守ることです
これが、そもそも「プライベート」と「保護」が存在する理由です。もちろん、実装でそれらを使用する必要があります-私が使用しないのは、実装に動作がない場合だけです(この場合、実際には実装ではありません)。
なぜならprivate
、より優れたデータカプセル化を意味するからです。
ばかげているように思えますが、作業中のインターフェイスを非常に簡単に定義する方法があります。
class Interface;
class Concrete { public: .... private: Interface* m_interface; }
class ConcreteFoo: public Interface {};
ConcreteBar
主な利点は、いつでも別のものに交換できることです。実際、これはPimpl
とStrategy
パターンの組み合わせであり、 のコンストラクターは、有効なオブジェクトを提供する役割を担うConcrete
a を呼び出します。Factory
ハートを実装する 2 番目の方法が思いつかない場合は、それをクラスにカプセル化してください。このようにして、後でリファクタリングする必要がある場合はInterface
、まったく同じメソッドセットで抽象を作成し、いくつかのポインター (およびコンストラクター) を変更するだけで問題ありません;)
(質問を誤解していたので、回答を変更しています。)
pimpl を持つクラスが指す実装クラスは、通常のクラスである必要があり、他のクラスと同様にプライベートな詳細を隠す必要があります。実際、多くの場合、既存のクラスであり、後で pimpl レイヤーを追加して依存関係を壊し、おそらくインターフェースを少し単純化します。