2017-12-12 11 views
0

私は以下のデザインを持っています: - クラスMの保護されたメンバを持つ1つのクラスA - Aから継承しクラスのオブジェクトへのポインタを持つ1つのクラスB C - 1個のクラスCC++継承チェーンからメンバへのアクセスを取得する

class A { 
public: 
    A() : _member(0) {} 
    ~A() { delete _member } 
protected: 
    M _member; 
} 

class B : public A { 
public: 
    B(){} 
    ~B(){} 
protected: 
    C* c; 
} 

class C { 
    // C needs to have access to _member 
} 

何のデザインは、この問題を解決するために、より適切であるべきクラスのメンバへのアクセスを持っている必要がありますか?

+0

標準的な回答は、たとえば、提供することによって_メンバーへのアクセスを管理することです。セッターメソッドとゲッターメソッド。 CはAまたはBとの関係がないように継承チェーンが構築されているため、「友人」はコード全体のアクセスパターンを汚染し、他の意図しないアクセス権を付与する可能性があります。 – StarShine

答えて

1

純粋なオブジェクト指向の用語では、クラスが別のクラスの内部フィールドに直接アクセスできるようにすることは悪い習慣です。つまり、C++は純粋なOO言語ではなく、これを(OOからの他の重要な逸脱の中でも)許しています。

プライベートメンバーに別のクラスへのアクセスを許可するには、そのクラスをフレンドに指定する必要があります。ただし、フレンドシップは派生クラスには渡されないため、クラスを必要なタイプにアップキャストする必要があります。

これはあなたの最も簡単な解決策である。このように

class A { 
public: 
    A() : _member(0) {} 
    ~A() { delete _member } 
protected: 
    friend class C; 
    M _member; 
} 

class B : public A { 
public: 
    B(){ c = new C(this); } // this call will cast the B* to an A* (important) 
    ~B(){ delete c;} 
protected: 
    C* c; 
} 

class C { 
public: 
    C(A* a) { _a->_member = new M(); } //Now C can directly access _member in A 
} 

Aから導出された任意のオブジェクトは、バックA*になって、_memberにアクセスするために使用することができます。

しかし先に述べたように、友情が継承されないよう、_memberへのアクセスを得るませんCから派生したクラスは、これより包括的なソリューションが必要とされています。このように

class M { 
public: 
    void Foo() { printf("Foo called\n"); } 
}; 
class A { 
    M* m; 
    friend class C; 
public: 
    A():m(0) { ; } 
}; 
class B :public A { 
    int id; 
public: 
    B() { id = 0; } 
}; 

class C { 
public: 
    C() { _a = 0; } 
    C(A* a) { _a = a; } 
protected: 
    M* getM() { return _a->m; } 
    void setM(M* m_) { _a->m = m_; } 
private: 
    A* _a; 
}; 
class D : public C { 
public: 
    D(B* b): C(b) { 
    } 
    void Foo() { 
     setM(new M()); 
     getM()->Foo(); 
     delete getM(); 
     setM(nullptr); 
    } 
}; 

int main() 
{ 
    B* b = new B(); 
    D d(b); 
    d.Foo(); 
    delete b; 
    getchar(); 
    return 0; 
} 

は、何のクラスは派生しませんfrom Aは_memberへの直接アクセスを提供し、Cから派生したクラスは直接アクセスできませんが、メンバ変数はCの保護されたAPIを介してアクセスできます。これにより、他の外部オブジェクトがそのオブジェクトにアクセスすることも防止されます。

+0

あなたの答えと推奨をありがとう。 – klaus

1

ACfriendを行います

class A { 
    friend class C; 
    /*and so on*/ 

その後Cは、彼らがprivateであっても、A内のすべてのメンバ変数と関数を見ることができます。

+0

ありがとうございます。実際には問題を簡略化し、AとBの間にさらにクラスがあるので、これらのクラスのすべてに友情を置く必要があります。 (私は本当にこれをしたくない...) – klaus

+0

友情は継承されないので、Bを経由してMにアクセスしようとするとうまくいかないことに注意してください。 –

+0

@klaus、クラス 'F'を導入することができます。そのうち' A'はフレンドで、 'F'を継承し、' F'のメンバー関数を提供して適切なメンバーを取得します。 – Bathsheba

関連する問題