2009-07-08 18 views
3

私はしかし、私はクラスBの友人Bのdoesnを持つC++のカプセル化技術

を継承したい適切のみクラスB

によって操作されなければならないクラスAを、カプセル化しようとしています仕事はできません - 友情は継承されません。

私が欲しいものを達成するために一般に受け入れられている方法は何ですか、または私は間違いを犯していますか?

クラスAは複雑なシステムの状態を表します。これは、クラスAの状態を変更するために適用できるアクションであるBによってのみ変更する必要があります。

+1

あなたの「システム」の「状態」が「行動」になるという論理的な理由はありません。 – Alex

+0

あなたはBにAがあり、CがAから継承すると、CはまだA(Bのメンバフィールド)にアクセスできると言っていますか? – codingbear

+0

彼は素晴らしいAを尊敬する人がいると言っていると思うし、それを修正する必要がある小さなBとC/D/Eがたくさんあります。 C/D/EはすべてBの派生クラスです –

答えて

3

あなたはBの子孫がAに直接アクセスできるようにしたいと思いますか?AとBが緊密に結合されている場合、Aを独立した定義ではなく、B自身の中で保護されたクラス定義にすることができます。例えば。

class B 
{ 
protected: 
    class A 
    { 
    }; 
}; 

もう1つのアイデアは、BのアクションをA.E.G.に委譲する保護されたメソッドを作成することです。

class A 
{ 
friend class B; 
private: 
    void DoSomething(); 
}; 

class B 
{ 
protected: 
    void DoSomething(A& a) { a.DoSomething(); } 
}; 
4

再設計が必要なようですが、クラスAは状態を表しますが、クラスBは一連のアクションを表します。そこには関係がありますが、それは継承関係ではありません。私は構成を提案したい。私が知る限り、あなたはISA関係よりもHASA関係をもっと望んでいます。

+0

同じことを考えていましたが、十分な情報を与えていないかどうかは分かりません – Alex

+0

これは、クラスBがクラスAの複数のインスタンス(複数の状態)。 http://en.wikipedia.org/wiki/State_pattern –

+0

私はそれを理解しているので、彼はAをシステムに、BをBの代わりにAから継承するために、異なるアクションが継承する基本クラスにしたいと考えています。 – Ari

2

これを実行する最も簡単な方法は、Bを持っているだけであるAが含まれています。

クラスB { が保護: A_。 };

次に、Bから継承し、Aを操作できるクラスCを書くことができます.Cが任意のことをAに行うことができない場合は、AをBでプライベートにし、 BはCが承認されたものをAに行うために次のように使用できます。

クラスB { プライベート: A a_; protected: void doSomethingToA(); };

+0

彼はクラスBから継承します。 – Partial

+0

私はこれが好きではありません。それはA(システム)がB(アクション)の一部である、つまりアクションがシステムを持っていると言います。これは意味がありません。 – Ari

+0

ええと、アリはこれについて正しいかもしれませんが、OPの意図が何らかの明確化なしで何であったかを知ることは難しいです。 – aem

0

私があなたが継承したい理由がわかりません。 Aのすべてをプライベートにし、友人B. Bは自由に操作できるAのメンバーを持っています。

2

すべてをそのまま維持するのが最も簡単なことは、Aに必要なAの同等の機能にアクセスできるBに保護されたメソッドを追加することです。これにより、Bのサブクラスだけにカプセル化が開かれます。

3

正しく理解すれば、B があり、それは派生品であるはクラスAの内部実装にアクセスできますか?

残念ながら、C++には、C#やJavaのような言語の「内部」保護レベルの概念はありません。

不透明ポインタとも呼ばれるprivate implementation paradigm(pimpl)を使用して、AおよびBのコンシューマには表示されないパブリックアクセスレベルを使用してシステム内の機能を公開することを検討できます。

+0

+1、これはPimplの良いユースケースだと思います。 –

0

これを説明する方法では、継承よりも構成に似ています。例えば。

class ComplexMachine { 
    public: 
    setState(int state); 
}; 

class Operator { 
    public: 
    Operator(ComplexMachine & m) :_m(m) {}; 

    void drive() { _m->setState(1); } 
    void turn() { _m->setState(2); } 
    void stop() { _m->setState(0); } 

    private: 
    ComplexMachine _m; 
}; 

class SmoothOperator : public Operator { } 
1

封じ込めBがAでいくつかのvirtualsをを上書きする必要がある場合を除き private継承が最も近いものであり、その場合には、(クラスBは、タイプAのプライベートメンバを含む)移動するための方法です。

0

あなたが与えられている情報のビットを使用した作業:

クラスBは、クラスAの不変量を維持するための責任を負わなければならない、とクラスBはA.どれでもクライアントを操作するための唯一の方法でなければなりません - 導出クラスまたは呼び出し元 - Aが存在することを知る必要はありません。

は(設計POVから、存在するのにも、一切必要ありませんが、私は十分に私はあなたに対してそれを保持していますこのような分離のための実用的な理由が発生した;)

これが必要な場合があります)書き込まれるべき定型コードの多く、またはインターフェイスのトリッキーなものがあります。例えばクライアントがクラスAを使用して情報を照会することは許可されていますが、それを変更しない場合、Bは集約されたAにconst &を渡すことができます。__declspec(プロパティ)または類似のものをサポートするコンパイラでは、

0

あなたの質問からわかるように、多型が必要です。 抽象クラスAを必要とし、クラスBはクラスAを継承する必要があります。キーワードを使用すると、特定の情報へのアクセス権を継承しながら同時に他のものへのアクセスを拒否するクラスを許可します。ここで少し例を示します。cplusplus.comから取ら

// dynamic allocation and polymorphism 
#include <iostream> 
using namespace std; 

class CPolygon { 
    protected: 
    int width, height; 
    public: 
    void set_values (int a, int b) 
     { width=a; height=b; } 
    virtual int area (void) =0; 
    void printarea (void) 
     { cout << this->area() << endl; } 
    }; 

class CRectangle: public CPolygon { 
    public: 
    int area (void) 
     { return (width * height); } 
    }; 

class CTriangle: public CPolygon { 
    public: 
    int area (void) 
     { return (width * height/2); } 
    }; 

int main() { 
    CPolygon * ppoly1 = new CRectangle; 
    CPolygon * ppoly2 = new CTriangle; 
    ppoly1->set_values (4,5); 
    ppoly2->set_values (4,5); 
    ppoly1->printarea(); 
    ppoly2->printarea(); 
    delete ppoly1; 
    delete ppoly2; 
    return 0; 
} 

コード(あまりにも多型と抽象クラスの情報が含まれています)。

0

BのみがAで動作するようにするには、Aのインスタンスをプライベートにして、保護されたインターフェイスをBからその子孫に公開します。

class A 
{ 
    public: 
    void foo() {} 
}; 

class B 
{ 
    private: 
    A a; 

    protected: 
    void CallAFoo() { a.foo() }; 
}; 

class C : public B 
{ 
    void goo() { CallAFoo(); } 
};