2017-11-30 5 views
1

ベースクラスを使用する場合でも、「マイ」コードだけがクラスを使用できるようにするにはどうすればよいですか? (それは基底クラスとして使用されていない場合、私はそれ私のクラスのいずれかのprivateまたはprotected入れ子になったクラス作ることができます)プライベートベースクラスとして使用されるクラスの一般的な使用を防止する

私は私のクラスのいずれかの基底クラスの使用は単なる実装の詳細であることを示すためにしたい場合明らかでない私はBaseクラスを使用したことを、私のDerivedクラスのクライアントに

class Base 
{ 
     ... 
} 

class Derived: private Base 
{ 
public: 

     Derived(...): Base{...} {... }; 

     ... 
} 

::、私はプライベート基本クラスを使用することができます

#include "Derived.h" 

void client() { 
    Derived d{...}; 
    Base *b = static_cast< Base * >(&d);// error 
    ... 
} 

しかし、それを想像しますクラスは非常に特殊化されているか、混乱している、または使用するのが難しいです。私のコードのクライアントがそれを基本クラスとして使用したり、そのクラスのオブジェクトを作成することはできません。このようなクライアントコードが失敗したので、私は、私のコードのいくつかに、それはある意味では、「プライベート」になりたい:

#include "Derived.h" 

class Client: Base// error wanted here 
{ 
public: 
    Client(...): Base{...} {...}; 

    ... 
} 

void client() 
{ 
    Derived d{...};// OK 
    Base b{...};// error wanted here 
    Client c{...};// error wanted here 
} 

はどのように私はそれを行うことができますか?

Java's package-private classesのように、同じ「パッケージ」(モジュール)内の他のクラスのみにアクセスできますが、「パッケージ」以外のコードでは使用できないようにするにはどうすればいいですか?

答えて

3

「プライベート」エンティティをdetail名前空間に配置することで、これを「遵守」することができます。多くの人気のあるライブラリ(例えばブースト)次の操作を行います。

namespace detail 
{ 
    class Base { /* ... */ }; 
} 

class Derived : private detail::Base 
{ 
    /* ... */ 
}; 
モジュールは、この問題は、あなたがコントロールすることができるようになりますよう、適切に解決される標準化されます

エンティティは、エクスポートされ、どれが実装され得るもの詳細。

+0

これは何も成し遂げません。クライアントは単に 'detail :: Base b = {...};'と書くことができます。 – Raedwald

+3

@ Raedwald:いい方法はありません。 C++の開発者は、 'detail ::'と書いた場合、慣習上、すべての賭けは無効であることを知っておくべきです。 libstdC++の奇妙な実装エンティティを使用することから、あなたが今日中止することは何もありません。 –

2

これは、Javaで行うのと同じように直接行うことはできません。代わりに、あなたが本当にそれはですBaseを使用する可能性を回避したい場合

namespace hidden { 
    class Base { 
    .. 
    }; 
} 

class Derived : private hidden::Base { 
    ... 
}; 

:それは混乱を回避する唯一の問題だ場合、あなたはあなたのコードのクライアントによって無視されることを意図された名前空間、例えば内部のBaseを移動することができますBaseを複数のクラスの親として使用する予定がある場合は、かなり難しい話です(その量は時間とともに変化する可能性があります)。あなたはBaseprivateコンストラクタを与え、あなたの派生クラスのそれぞれであることを示している可能性がありfriendBaseの:これはあなたがBaseから派生する各新しいクラスのためのマニュアルのメンテナンスが必要です。もちろん、

class Hider { 
    private: 
    Hider() = delete; 
    class Base { 
     .. 
    }; 

    friend class Derived; 
}; 

class Derived : Hider::Base { 
    .. 
}; 

+0

基本クラスを別のクラスのプライベートメンバーにすることはできません。それを使用する友人のもの? – UKMonkey

+0

@UKMonkeyどのようにそのクラスを非表示にするには? – Ivan

+0

@Ivanなぜ 'コンテナ'クラスが隠されているかどうか気になりますか?誰かがそのインスタンスを作成しようとするとコンパイルエラーが発生するようにすることができます – UKMonkey

1

あなたはそれを100%を施行したい、そして私はこれがコールのあなたのポートであると信じて「『_』で始まるものを使用しないでください」のpythonの方法が気に入らない場合:

class Dave; 

class MyPrivateBaseClasses { 
    private: 
    MyPrivateBaseClasses(); // ensure nothing can use this class 
    class BaseClassA {}; 

    friend Dave; 
}; 

class Dave : public/private MyPrivateBaseClasses::BaseClassA 
{}; 

確かに - それはあなたがそれを使用したいすべてのものを友人に持っていなければならないことを意味しますが、 BaseClassAを使用している人に対する100%保護。

+0

エンドユーザープログラマが自分のタイプを自分自身に追加するなど悪意のあるものから保護することはほとんどありません。リスト。正直なところ、私が考えることができる本当の唯一の保護は、隠された基底クラスのソースを配布しないことですが、実行可能ではないかもしれませんし、保護する必要のある悪意のあるレベルによってはまだ十分ではないかもしれません。もちろん、私はあなたがその悪意の程度から守る必要がある場合、他の誰かがコンパイルするためのソースを配布しているのですか? – SoronelHaetir

+0

さて、それは人々がコードを編集するのを妨げるわけではありませんが、コードを編集することなく人々がコードを使用するのを防ぐことができます。他の答えに応じて名前空間を使用するには、クラスを使用するコードを編集する必要はありません。 – UKMonkey

関連する問題