0

ライブラリのユーザーに対して実装の詳細を隠すことができるように、pimpl イディオムを使用してクラス ライブラリを作成したいと考えています。

内部からのみ呼び出し可能なメソッドを持ちながら、一部のメソッドがパブリックでユーザーの観点から呼び出し可能なクラスを作成することは可能ですか?

今のところ、friend キーワードを使用し、内部メソッドを private と宣言するソリューションしか見当たりません。

例: MyPartiallyVisibleClass: ユーザーがアクセスできるメソッドと、ライブラリの内部のみがアクセスできるメソッドが混在するクラス。InternalClass: ライブラリ内の内部クラス。ユーザーはこれが存在することを決して知りません。

// MyPartiallyVisibleClass.h: Will be included by the user.
class MyPartiallyVisibleClass
{
private:
    class Impl;          // Forward declare the implementation
    Impl* pimpl;

    InternalMethod();    // Can only be called from within the library-internals.

public:
    UserMethod();       // Will be visible and callable from users perspective.
}

// MyPartiallyVisibleClass.cpp
class MyPartiallyVisibleClass::Impl
{
private:
    InternalMethod();

public:
    UserMethod();

    friend class InternalClass;
}

// Internal class that will not be included into users application.
class InternalClass
{
public:
    InternalMethod()
    {
        MyPartiallyVisibleClass pvc;
        pvc.InternalMethod();
    }
}

これを行うより良い方法はありますか?

4

1 に答える 1

0

長所と短所があります。

ソースの観点から見ると、ヘッダーとバイナリのみを配布すると、cpp ファイル内のすべてがソース ユーザーに表示されません。

そのため、これもMyPartiallyVisibleClass::Impl::Usermethod表示されませんが、宣言されている cpp ファイル内のどこでも呼び出し可能で公開されています。

外部メソッドを内部で繰り返したくない場合は、外部クラスと内部クラスの間のゼロウェイ、一方向、または双方向の友情が必要になる場合があります。カプセル化が壊れているように見えるかもしれませんが、そうではありません。ここでの「カプセル」は外部クラスだからです。内部プライバシーの複雑なヒエラルキー (パブリック外部、プライベート外部、パブリック内部プライベート内部パブリック、さらに内部など) を作成すると、すべてが同じ責任の下にある場合、無知になる可能性があります。内部部分が大きすぎて別の開発者に割り当てられない限り、別のレベルのインターフェースと実装が必要になります。

ただし、バイナリユーザーの観点から見ると、インライン化されていないすべての関数が存在し、-外部リンケージを持っている-その名前はライブラリで使用できるため、他のソースで公開する別のヘッダーを作成することで「呼び出し可能」になります。私は文書化されていない機能になります。

パブリック/プライベートなどの概念は、コードの安全性のためのものです (常に同じ「コントラクト」を利用できるように維持することを約束したくない機能を避け、外部コードをより安定させ、不要な依存関係を排除します)。 」(電話をかけたい人を避けて、電話をかける方法を見つけます)。

また、別の欠点もあります。テンプレートをソースに隠すことはできません。これは、テンプレートを (開発者のバイナリ空間ではなく) ユーザーのソース コード空間に展開する必要があるためです。そして、ジェネリック プログラミングや関数型の静的ポリモーフィズムなどの成長により、pimpl イディオムはますます魅力的ではなくなります。

今日、単一の cpp ファイルによって作成された多くのプログラムがあり、単一の「マネージャー オブジェクト」をインスタンス化します。このオブジェクトは、ヘッダーのみのライブラリで構成されているため、その機能全体が常駐しています。信じられないかもしれませんが、この方法でプログラミングすると、コンパイラ間でコードの移植性がさらに高まります。これは、考えられるクライアント コンパイラごとに異なるバイナリ形式で存在する必要がないためです。また、必ずしもビルド時間が長くなるわけではありません。あまり頻繁に変更されないコードに対して、プリコンパイル済みヘッダーを 1 回生成できます。ユーザーがコードを見ることができるかどうか誰が気にしますか? 彼がそれを使用してサポートされたい場合、それを不適切に変更することは彼の関心事ではありません. 彼がハッキングしたり盗んだりしたい場合は、とにかく別の方法を見つけます。

于 2013-08-18T07:41:56.000 に答える