Pergunta

Eu tenho uma classe (classe A) que é projetado para ser herdada por outras classes escritos por outras pessoas. Eu também tenho outra classe (classe B), que também herda de uma.

B tem para aceder a algumas funções de membro de A que não devem ser acessados ??por outras classes que herdam.

Assim, as funções de membro destes de A deve ser público para B, mas privado para os outros.

Como posso resolvê-lo sem o uso de directiva 'amigo'?

Obrigado.

EDIT:. Exemplo por que eu precisar dele

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!
  }
};
Foi útil?

Solução

O que você diz é: existem dois conjuntos de subclasses de A. Um conjunto devem ter acesso, o outro conjunto não deveria. Parece errado para ter apenas uma marca de subclasses (ou seja, B) 'ver' os membros de A.

Se o que você quer dizer é:. Única que pode usar este parte da funcionalidade, enquanto que nossos clientes não podem, há outros resorts

(reutilização funcionalidade por herança muitas vezes cantos lo com este tipo de problemas. Se você vai para reutilização por agregação, você pode obter em torno dele.)

Uma sugestão:

// 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 {
};

Mas melhor seria seguir o caminho de agregação, e dividir a corrente de "A" em uma visível e uma parte invisível:

class InvisibleFunctionality {
};

class VisibleFunctionality {
};

class B {
    InvisibleFunctionality m_Invisible;
    VisibleFunctionality m_Visible;
};

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

Outras dicas

Você não pode. Isso é o que amigo é para.

Uma alternativa seria a de alterar o design / arquitetura do seu programa. Mas, para sugestões sobre este eu precisaria de mais algum contexto.

Bem - se você quer exatamente o que você descreveu, então amigo é a melhor solução. Cada padrão de codificação não recomenda o uso de amigo , mas onde o projeto alternativo é mais complexa -. Então talvez vale a pena fazer uma exceção

Para resolver o problema sem amigo exigirá uma arquitetura diferente

Uma solução poderia ser a de usar uma forma dos deriva Pimpl idioma onde 'B' do objeto de implementação interna, enquanto os outros clientes derivam da classe externa.

Outra poderia ser a de colocar uma camada extra de herança entre 'A' e os "outros clientes". Algo como:

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
};

No entanto, esta solução ainda tem o seu problemas. 'ARestricted' não pode converter para um 'A' de modo que este teria de ser resolvido por algum outro "getter" para 'A'. No entanto, você pode nomear esta função de tal maneira uma vez que não pode ser chamado acidentalmente:

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

Depois de tentar pensar em outras soluções, e assumindo que as suas necessidades de hierarquia a ser como você descreve, eu recomendo que você acabou de usar amigo !

EDIT: Então xtofl sugeriu renomear os tipos 'A' a 'AInternal' e 'ARestricted' para 'a'.

que funciona, exceto eu notei que 'B' não seria mais um 'A'. No entanto, AInternal poderia ser herdada virtualmente - e, em seguida, 'B' pode derivar tanto 'AInternal' e '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);
}

É claro que agora você tem bases virtuais e herança múltipla! Hmmm .... agora, é que melhor ou pior do que um único amigo declaração?

Eu acho que você tem um problema maior aqui. Seu projeto não parece som.

1) Eu acho que a construção 'amigo' é problemático para começar

2) se 'amigo' não é o que você quer é, você precisa re-examinar o seu design.

Eu acho que você quer necessidade de fazer algo que só começa o trabalho feito, usando 'amigo' ou desenvolver uma arquitetura mais robusta. Dê uma olhada na alguns padrões de design , eu tenho certeza que você vai encontrar algo útil.

EDIT:

Depois de ver o seu código de exemplo, você definitivamente precisa de re-arco. Classe A podem não estar sob o seu controle, de modo que é um pouco complicado, mas talvez o que quer para re-fazer classe B para ser um "tem-um" classe em vez de um "é-um" classe.

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
    }

};

Eu acho isso um desafio interessante. Aqui está como eu iria resolver o problema:

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;
}

Se você estava indo para usar esse tipo de padrão o tempo todo, você pode reduzir o código usando modelos.

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;
}

Se eu entender:

  • A será uma subclasse por outros desenvolvedores.
  • B vai ser uma subclasse por outros desenvolvedores e herda de uma.
  • A tem alguns métodos que você não quer acessível a desenvolvedores externos através B.

Eu não acho que isso pode ser feito sem o uso de amigo. Não há nenhuma maneira que eu conheço para fazer os membros de uma superclasse disponível apenas para herdeiros diretos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top