2010-11-23 16 views
0

私は適切な解決策が見つからない場合があります。テンプレートベースクラスと、そのベースクラスにいくつかの作業を行うマネージャクラスが必要です。ここでは、コード変数のアクセス修飾子:プライベート対プロテクト

class Base; 

class Manager 
{ 
public: 
    void DoSomethingTo(Base * bclass) 
    { 
     if(bclass->PrivateVar == 0) 
      // Some code 
    } 
} 

class Base 
{ 
protected: 
    int PrivateVar; 
friend class Manager; 
}; 

template<class T> 
class TempBase : public Base 
{ 
private: 
    Manager * man; 
public: 
    void DoWork() 
    { 
     PrivateVar = 0; 
     man->DoSomethingTo(this); 
    } 
} 

私の問題はPrivateVar変数が実際にTempBaseにプライベートにとTempBaseから派生したクラスからづけしてはなりませんが、私はManager::DoSomethingTo()へのポインタを渡すことができないので、私はベースからそれを導出する必要がありさクラスとベースクラスはPrivateVarを所有していなければなりません。また、私はTempBaseでPrivateVarを使用するので、Baseにプライベートにすることはできません。これにより、TempBaseの子クラスからアクセスできるようになります。

PrivateVarがプライベートメンバーであり、Manager::DoSomethingTo()からアクセスできるように、TempBaseクラスを作成するにはどうすればよいですか?

おかげ

答えて

1

Base内のアクセス保護を削除し、個人的に継承します。

class Manager 
{ 
public: 
    void DoSomethingTo(struct Base * bclass); 
}; 

struct Base 
{ 
    int PrivateVar; 
}; 

void Manager::DoSomethingTo(struct Base * bclass) 
{ 
    if(bclass->PrivateVar == 0) 
     ; // Some code 
} 

template<class T> 
class TempBase : private Base 
{ 
private: 
    Manager * man; 
public: 
    void DoWork() 
    { 
     PrivateVar = 0; 
     man->DoSomethingTo(this); 
    } 
}; 
0

あなたはベース自体に保護されたメンバ関数を入れることができます:

class Base 
{ 
protected: 
    void sendPrivateVarToManager(Manager& manager) 
    { 
     manager.DoSomethingToPrivateVar(privateVar); 
    } 
}; 

をベースに実装が実際に基地の外に置くことができ、テンプレートではないので。

その他の問題は、privateVarがBaseに存在し、TempBaseには表示されますが、階層の下には表示されません。あなたはそれを実装しなければならないが、sendPrivateVarToManagerをそのクラスに入れることもできますし、privateVarをパラメータとして渡すこともできます。あなたの他の選択肢は、TempBaseをBaseの友人にすることですが、それは間違っているようです。なぜTempBaseにアクセスする必要があるのか​​分かりません。

+0

デザインからは、なぜ「Base」にアクセスする必要があるのか​​わかりません。どうやら 'PrivateVar'は純粋に' TempBase'のもので、 'Base'に移動して' Manager'がアクセスできるようになっています。私はコードを読んでスパゲッティの皿を解く印象を受けました:/ –

+0

@Matthieu M .:「ベース」にアクセスが必要な理由はあなたが絶対に正しいです。そして、面倒なコードについてはごめんなさい。 –

+0

@Bahadir:技術的な問題を抱えていると、当然設計に反映される傾向がありますのでご安心ください。私は自分自身のいくつかの歪んだデザインを主張することができます、私はまだ維持の名誉を持っていることを願っています:D –

2

すべての最初に、火炎戦争を始めましょう:

protectedされるクラスの属性の理由は決してありません。それはprivate(ほとんどの場合)か、おそらくいくつかの角の場合publicになります。すべての派生クラスでprotected属性を見ることになるので、protectedだけ誤った安心感をもたらすことに注意してください:1はprotected属性上の任意の不変を制御することはできませんので、基本的にpublic一つだ、コメントとの上にをタッチしないでください。それ。さて、これは、私は単純にこれを変更することを提案すると述べたと行われていること

:変数の所有者にテストの責任を委譲することで

class Base {}; 
template <typename T> class TBase; 

class DoKey { template <typename T> friend class TBase; DoKey(); }; 

class Manager 
{ 
public: 
    void DoSomethingTo(Base& base, DoKey const& key); 
}; 

template <typename T> 
class TBase: public Base 
{ 
public: 
    void Do() 
    { 
    Manager manager; 
    if (PrivateVar == 0) { manager.DoSomething(*this, DoKey()); } 
    } 

private: 
    int PrivateVar; 
}; 

は、私たちは優しく周りのすべてのサークル当社心配。もちろん、同様の方法で複数のクラスを動作させる必要がある場合は、に純粋な仮想のvoid ShouldIDoSomething() constを導入し、Managerの方法で確認できます。

+0

私はDoKeyが何であるかについてはわかりません。 –

+1

@Bahadir:アクセスコントローラです。 'DoKey'によってフレンドとして宣言されたクラスだけが' DoKey'インスタンスを構築することができ、 'Manager'クラスの' DoSomethingTo'メソッドを呼び出すことができます。これは、 'Manager'で直接' friend'を使う代わりに、クラス内部全体ではなく1つのメソッドへのアクセスを許可し、依存関係を減らします。 –

0

PrivateVarを非公開にして、TempBaseManagerの友人をBaseにすることができます。 hereを参照してください。このコードは最もクリーンなコードではありません。

0

私は、PrivateVarをTempBaseに保ちながら、PrivateVarを取得するために、パブリックの純粋仮想関数をBaseに置くことができると考えました。

class Manager 
{ 
public: 
    void DoSomethingTo(Base * bclass) 
    { 
     if(bclass->GetPrivateVar() == 0) 
      // Some code 
    } 
} 
class Base 
{ 
private: 
virtual int GetPrivateVar() = 0; 
friend class Manager; 
}; 

template<class T> 
class TempBase : public Base 
{ 
private: 
    Manager * man; 
    int PrivateVar; 
    int GetPrivateVar() {return PrivateVar;} 
public: 
    void DoWork() 
    { 
     PrivateVar = 0; 
     // Some code 
     man->DoSomethingTo(this); 
     // Some code 
    } 
friend class Manager; 
} 
関連する問題