2017-12-12 10 views
0

다음과 같은 디자인이 있습니다. - 클래스 M의 보호 된 멤버가있는 클래스 A - A에서 상속 받고 클래스의 객체에 대한 포인터가있는 하나의 클래스 B C - 하나의 클래스 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

일반적인 답은 _member에 대한 액세스를 관리하는 것입니다. setter 및 getter 메소드 C가 A 또는 B와 관계가 없도록 상속 체인이 구성되므로 "친구"는 코드 전체에서 액세스 패턴을 오염시키고 다른 의도하지 않은 액세스 권한을 부여 할 수 있습니다. – StarShine

답변

1

순수 OO 용어에서 클래스가 다른 클래스의 내부 필드에 직접 액세스하도록 허용하는 것은 좋지 않습니다.

즉, 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

C을 확인 friendA의 :

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

그런 다음 C들이 private을 경우에도, A의 모든 멤버 변수와 함수를 볼 수 있습니다.

+0

고맙겠 습니다만, 현실적으로 저는 문제를 단순화 시켰고 A와 B 사이에 더 많은 클래스가있어서 모든 클래스에 우정을 쌓아야합니다. 맞습니까? (그리고 저는 이것을 정말로하고 싶지 않습니다 ...) – klaus

+0

우정은 상속되지 않으므로 B를 통해 M에 접근하려고 시도하면 작동하지 않습니다. –

+0

@klaus,'A'가 친구 인'F' 클래스를 소개하고'F'를 상속하여'F'의 멤버 함수를 제공하여 적절한 멤버를 얻을 수 있습니다. – Bathsheba