5

pimpl イディオムを使用していくつかのクラスを実装していますが、いくつかの設計上の問題に遭遇しています。

まず、私はいつもニキビがこのように行われるのを見てきました

class Object
{
public:
    Visible();
    ~Visible();
 .. etc ..
private:
    class ObjectImpl *_pimpl;
};

私はこのアプローチを使用するいくつかのクラスを持っていますが、私の問題は、これらのクラスのいくつかがお互いの実装の詳細にアクセスする必要があることですが、_pimpl ポインターはプライベートに宣言されています。

_pimpl public を宣言することのマイナス面を誰でも見ることができますか。明らかに、公開されている場合、誰かが誤って (または故意に) 再割り当てする可能性があります。(「プライベート」を「パブリック」として#定義して、とにかくアクセスを許可することができるという事実を無視しています。これを行うと、得られるものに値します)。

私のデザインに欠陥があるかもしれませんが、その点についてのコメントも歓迎します。

Object を完全に定義せずに Object::ObjectImpl を前方宣言することはできないため、友人を使用することは本当に嫌いです。

すなわち

 ...
 private:
    class ObjectImpl *_pimpl;
    friend class OtherObject::OtherObjectImpl; // this needs a fully qualified OtherObject
};

Thxマーク。

* 更新 - 詳細 **

Command と呼ばれるクラスと Results と呼ばれるクラスの 2 つのクラスがあります。結果のベクトルを返す Command のメソッドがあります。

Command と Results はどちらも pimpl イディオムを使用します。リザルトへのインターフェースをできるだけ小さくしたい。

class Command
{
public:
    void getResults( std::vector< Results > & results );
    void prepareResults( std::vector< Results > & results );
private:
    class CommandImpl *_pimpl;
};

class Results
{
public:
    class ResultsImpl;

    Results( ResultsImpl * pimpl ) :
        _pimpl( impl )
    {
    }

private
    ResultsImpl *_pimpl;
};

Command::getResults() に追加されました。ResultsImpl を結果に挿入します。Command::prepareResults() では、ResultsImpl にアクセスする必要があります。

M.

4

4 に答える 4

7

実装を公開する正当な理由があるとは思えません。公開メソッドを使用して、いつでも実装の機能を公開できます。

class Object
{
public:
   Object();
  ~Object();

  int GetImplementationDetail();

private:
  std::unique_ptr< ObjectImpl > _pimpl;
};

int Object::GetImplementationDetail()
{
  return pimpl->GetImplementationDetail();
}

それとは別に、クラスは 1 つのことだけを担当する必要があり、他のクラスへの依存関係は最小限にする必要があります。他のクラスがオブジェクトの pimpl にアクセスできるはずだと思う場合は、設計に欠陥がある可能性があります。

著者の更新に従って編集してください。あなたの例はまだかなりあいまいですが(または、少なくともその完全な意図を伝えることはできません)、イディオムを誤解しているようで、役に立たない場合に適用しようとしています。他の人が指摘したように、「P」はプライベートを表します。結果クラスはすべてパブリックであるため、プライベートな実装はあまりありません。したがって、上記の内容を使用して何も「注入」しないか、ニキビをすべてまとめて取り除き、Result クラスのみを使用してください。Result のクラス インターフェイスが非常に小さいため、別のクラスへのポインタにすぎない場合、この場合はあまり役に立たないようです。

于 2011-06-24T10:19:07.720 に答える
1

クラスがお互いの詳細に依存しているのはなぜですか? デザインを再考することができます。クラスは抽象化に依存する必要があります。

あなたのデザインが本当に適切であると考えるなら、次のような「source-file-private」ヘッダーを提供することを止めるものは何もありません:

include/
   foo.h
src/
   foo.impl.h
   foo.c
   bar.c

そして、foo.c と bar.c の両方に foo.impl.h を #include します。

foo.c:
    #include "foo.impl.h"
    ...

bar.c:
    #include "foo.impl.h"
    ...

しかし、繰り返しますが、一般的に、

依存性逆転の原則:

A. 高レベル モジュールは低レベル モジュールに依存すべきではありません。どちらも抽象化に依存する必要があります。

B. 抽象化は詳細に依存すべきではありません。詳細は抽象化に依存する必要があります。

また、 SOLIDGRASP、特に疎結合に関するポイントを必ず確認してください。

于 2011-06-24T10:20:54.807 に答える
0

データ メンバーを作成しても、他のクラスがその型の定義を認識_pimple publicない限り、何も得られません。これは、まさに Pimple が防止しようとしているものです。ObjectImpl

Object代わりにできることは、クラスにプライベート インターフェイスを追加することです。これにより、フレンドシップ クラスは、 Object.

もちろん、friendできるだけめったに使用しないツールであることに関する一般的な免責事項はすべて適用されます。

于 2011-06-24T10:21:35.380 に答える
0

It is unnecessary to qualify the friend thusly.

If you just use friend class OtherObject, then the OtherObject class may access the necessary internals.

Personally my Pimpl are just a struct (bundle of data) and I leave the methods to operate on it in the original class.

于 2011-06-24T10:27:17.303 に答える