문제

나는 다른 사람들이 쓴 다른 수업에 의해 상속되도록 설계된 수업 (클래스 A)이 있습니다. 또한 A에서 물려받는 다른 클래스 (클래스 B)도 있습니다.

B는 다른 상속 클래스에서 액세스 할 수없는 일부 A의 멤버 기능에 액세스해야합니다.

따라서이 A의 멤버 기능은 B에게 공개되어야하지만 다른 사람들에게는 개인이어야합니다.

'친구'지침을 사용하지 않고 어떻게 해결할 수 있습니까?

고맙습니다.

편집 : 필요한 이유.

class A
{
public:
  void PublicFunc()
  {
    PrivateFunc();
    // and other code
  }
private:
  virtual void PrivateFunc();
};

class B : public class A
{
private:
  virtual void PrivateFunc()
  {
    //do something and call A's PrivateFunc
    A::PrivateFunc(); // Can't, it's private!
  }
};
도움이 되었습니까?

해결책

당신이 말하는 것은 다음과 같습니다. 두 개의 서브 클래스 세트가 있습니다. 한 세트는 액세스해야하고, 다른 세트는해서는 안됩니다. 한 브랜드의 서브 클래스 (즉, B) 만있는 것은 잘못된 느낌이 듭니다.

당신이 의미하는 바는 다음과 같습니다 우리 사용할 수 있습니다 이것 기능의 일부는 고객이 할 수 없지만 다른 리조트가 있습니다.

(상속에 의한 기능 재사용 종종 이런 종류의 문제가 발생합니다. 집계에 의해 재사용되면 주변을 둘러 볼 수 있습니다.)

제안:

// separate the 'invisible' from the 'visible'.
class A_private_part {
protected: 
  int inherited_content();
public:
  int public_interface();          
};

class B_internal : public A_private_part {
};

class A_export : private A_private_part {
public:
    int public_interface() { A_private_part::public_interface(); }
};

// client code
class ClientClass : public A_export {
};

그러나 집계 방식으로 이동하고 현재 "A"를 가시적이고 보이지 않는 부분으로 나누는 것입니다.

class InvisibleFunctionality {
};

class VisibleFunctionality {
};

class B {
    InvisibleFunctionality m_Invisible;
    VisibleFunctionality m_Visible;
};

// client code uses VisibleFunctionality only
class ClientClass {
    VisibleFunctionality m_Visible;
};

다른 팁

당신은 할 수 없습니다. 그게 친구가있는 것입니다.

대안은 프로그램의 설계/아키텍처를 변경하는 것입니다. 그러나 이것에 대한 힌트를 위해서는 더 많은 맥락이 필요합니다.

글쎄 - 당신이 묘사 한 것을 정확히 원한다면 친구 최상의 솔루션입니다. 모든 코딩 표준은 사용하지 않는 것이 좋습니다 친구 그러나 대체 디자인이 더 복잡한 곳에서는 예외를 만들 가치가 있습니다.

친구없이 문제를 해결하려면 다른 아키텍처가 필요합니다.

한 가지 해결책은 PIMPL 관용구 여기서 'b'는 내부 구현 객체에서 파생되는 반면 다른 클라이언트는 외부 클래스에서 파생됩니다.

다른 하나는 'A'와 "다른 클라이언트"사이에 추가 상속 레이어를 배치하는 것일 수 있습니다. 같은 것 :

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

class B : public A {  // OK access to both 'foo' and 'bar'
};

class ARestricted : private A {
public:
  inline void foo () { A::foo (); };    // Forwards 'foo' only
};

그러나이 솔루션에는 여전히 문제가 있습니다. 'Arestricted'는 'a'로 변환 할 수 없으므로 'a'를 위해 다른 "getter"가 해결해야합니다. 그러나이 기능을 우연히 호출 할 수없는 방식으로 이름을 지정할 수 있습니다.

  inline A & get_base_type_A_for_interface_usage_only () { return *this; }

다른 솔루션을 생각하고 계층 구조가 설명되어 있어야한다고 가정 한 후에는 사용하는 것이 좋습니다. 친구!

편집하다: 그래서 XTOFL 유형 'a'로 'ainternal'으로 이름을 바꾸고 'a'로 'A'를 바꾸는 것을 제안했습니다.

'B'가 더 이상 'a'가 아니라는 것을 알지 못했습니다. 그러나 Ainternal은 사실상 상속 될 수 있으며 'B'는 'Ainternal'과 'a'에서 파생 될 수 있습니다!

class AInternal {
public:
  void foo ();
  void bar ();
};

class A : private virtual AInternal {
public:
  inline void foo () { A::foo (); };    // Forwards 'foo' only
};

// OK access to both 'foo' and 'bar' via AInternal
class B : public virtual AInternal, public A {
public:
  void useMembers ()
  {
    AInternal::foo ();
    AInternal::bar ();
  }
};

void func (A const &);

int main ()
{
  A a;
  func (a);

  B b;
  func (b);
}

물론 지금 당신은 가상베이스와 여러 상속이 있습니다! 흠 .... 이제, 단일보다 낫거나 나쁘다 친구 선언?

나는 당신이 여기에 더 큰 문제가 있다고 생각합니다. 당신의 디자인은 건전하지 않습니다.

1) 나는 '친구'구조가 처음에 문제가 있다고 생각합니다.

2) '친구'가 원하는 것이 아니라면 디자인을 재검토해야합니다.

나는 당신이 '친구'를 사용하여 일을 끝내거나보다 강력한 아키텍처를 개발해야한다고 생각합니다. 보세요 약간 디자인 패턴, 나는 당신이 유용한 것을 찾을 것이라고 확신합니다.

편집하다:

샘플 코드를 본 후에는 반드시 다시 시작해야합니다. 클래스 A는 귀하의 통제하에 있지 않을 수 있으므로 약간 까다로울 수 있지만 클래스 B가 "is-a"클래스 대신 "Has-A"클래스로 재발하고 싶을 수도 있습니다.

public Class B
{
    B() 
    {

    }

    void someFunc()
    {
       A a; //the private functions is now called and a will be deleted when it goes out of scope
    }

};

나는 이것이 흥미로운 도전이라고 생각한다. 문제를 해결하는 방법은 다음과 같습니다.

class AProtectedInterface
{
public:
    int m_pi1;
};

class B;
class A : private AProtectedInterface
{
public:
    void GetAProtectedInterface(B& b_class);

    int m_p1;
};

class B : public A
{
public:
    B();
    void SetAProtectedInterface(::AProtectedInterface& interface);

private:
    ::AProtectedInterface* m_AProtectedInterface;
};

class C : public A
{
public:
    C();
};

C::C()
{
    m_p1 = 0;
//    m_pi1 = 0; // not accessible error
}

B::B()
{
    GetAProtectedInterface(*this);

    // use m_AProtectedInterface to get to restricted areas of A
    m_p1 = 0;
    m_AProtectedInterface->m_pi1 = 0;
}

void A::GetAProtectedInterface(B& b_class)
{
    b_class.SetAProtectedInterface(*this);
}

void B::SetAProtectedInterface(::AProtectedInterface& interface)
{
    m_AProtectedInterface = &interface;
}

이런 종류의 패턴을 항상 사용하는 곳이라면 템플릿을 사용하여 코드를 줄일 수 있습니다.

template<class T, class I>
class ProtectedInterfaceAccess : public I
{
public:
    void SetProtectedInterface(T& protected_interface)
    {
        m_ProtectedInterface = &protected_interface;
    }

protected:
    T& GetProtectedInterface()
    {
        return *m_ProtectedInterface;
    }

private:
    T* m_ProtectedInterface;
};

template<class T, class I>
class ProtectedInterface : private T
{
public:
    void SetupProtectedInterface(I& access_class)
    {
        access_class.SetProtectedInterface(*this);
    }
};

class Bt;
class At : public ProtectedInterface <::AProtectedInterface, Bt>
{
public:
    int m_p1;
};

class Bt : public ProtectedInterfaceAccess<::AProtectedInterface, At>
{
public:
    Bt();
};

class Ct : public At
{
public:
    Ct();
};

Ct::Ct()
{
    m_p1 = 0;
    // m_pi1 = 0; // not accessible error
}

Bt::Bt()
{
    SetupProtectedInterface(*this);

    m_p1 = 0;
    GetProtectedInterface().m_pi1 = 0;
}

내가 이해한다면 :

  • A는 다른 개발자가 서브 클래스를 제공합니다.
  • B는 다른 개발자가 서브 클래스를 받고 A에서 물려받습니다.
  • A는 B를 통해 외부 개발자에게 액세스 할 수없는 몇 가지 방법이 있습니다.

나는 이것이 친구를 사용하지 않고 할 수 있다고 생각하지 않습니다. 수퍼 클래스 회원을 직접 상속자 만 사용할 수 있도록하는 방법은 없습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top