Qual é o caso de uso para usar a classe de amigo C ++?

8

Eu estou tentando entender amigo C ++. Quando é o bom caso de uso para usar amigo? Suponho que, se queremos permitir que outra classe tenha acesso aos atributos de outra classe, por que não a tornamos pública ou herdamos dessa classe?

Obrigado pela ajuda.

Joshua Partogi
fonte
4
Eu acho que essa pergunta definitivamente pertence aqui, pois é mais um "por quê?" pergunta do que um "como?" pergunta, e já houve alguns pontos positivos nas respostas.
Larry Coleman

Respostas:

14

Tornar um membro da classe publicsignifica conceder acesso a todos , quebrando completamente o encapsulamento.

Herdar de uma classe geralmente não é desejável, se a classe de amigo não for uma subclasse. Subclassificar apenas para ter acesso aos componentes internos de uma classe é um grave erro de design. E mesmo uma subclasse não pode ver os membros privados de sua classe base.

Um uso típico de friendé para operadores que não podem ser membros, como operadores de fluxo, operator+etc. Nesses casos, a classe real à qual estão associados não é (sempre) o primeiro parâmetro da função; portanto, a função não pode ser implementado como um método membro.

Outro exemplo é a implementação de um iterador para uma coleção. O iterador (e somente o iterador) precisa ver os elementos internos de sua coleção pai, no entanto, não é uma subclasse da coleção.

Péter Török
fonte
Às vezes, essas funções gratuitas de amigo são definidas em linha na classe.
Deduplicator
3

O exemplo para o qual eu mais frequentemente vi classes de amigos usadas em C ++ está no teste de unidade. Os testes de unidade geralmente querem saber tudo sobre seus internos, mas não fazem parte de você, e não faz sentido que eles tentem herdar de você.

Se você não está familiarizado com a escrita de testes de unidade, sugiro que você comece imediatamente.

btilly
fonte
6
As classes de produção não devem saber nada sobre as classes de teste de unidade. E os testes não precisam ver os internos da classe testada; uma classe bem projetada pode ser testada em unidade por meio de sua API pública. Caso contrário, provavelmente não é uma classe bem projetada (por exemplo, tenta fazer demais, portanto parte de sua funcionalidade deve ser melhor extraída em uma classe separada).
Péter Török
4
@ Peter-Torok: Isso depende do que "bem desenhado" significa para você. Um caso comum em que desejo acesso privilegiado é injetar zombarias para rastrear se as ações que deveriam ocorrer. Expor essas partes da estrutura de objetos na API pública parece uma grande violação do encapsulamento. Portanto, muitas vezes eu quero que o código de teste da unidade tenha acesso privilegiado.
btilly
1
@ btilly: Se você deseja injetar uma simulação, pode usar um parâmetro no construtor, sem necessidade de acessar os elementos internos da classe.
Giorgio
1
@ PéterTörök GTest discorda de você. Existem alguns casos em que um teste de amigo pode ser útil - por exemplo, é possível comparar a equivalência de dois objetos da mesma classe sem expor uma operação de equivalência na API (talvez por questões de segurança).
VF1
1
@Giorgio Sim, você pode tornar públicas as informações que deseja testar na unidade. Mas agora sua API pública cresceu e pode prendê-lo para criar decisões que seriam imprudentes no futuro. Em outras palavras, é apropriado fazer testes de unidade para os casos extremos da sua implementação atual. Nem sempre é apropriado expor esse nível de detalhe aos consumidores da sua classe.
btilly
0

Esta pergunta deve estar no stackoverflow. De qualquer forma, você usa um amigo apenas quando deseja compartilhar as partes privadas da sua classe com outra (s) aula (s), mas não com mais ninguém. Se você os tornar públicos, todos poderão ver suas partes íntimas (trocadilhos ;-P). Existem duas restrições importantes que reforçam a privacidade: 1) você precisa especificar quem é seu amigo. Ninguém mais pode ser um amigo. 2) você não pode herdar comportamento "amigável" nas subclasses da classe de amigos

DPD
fonte
1
Pergunta do método socrático: E por que é ruim todo mundo ver suas partes íntimas?
Larry Coleman
3
@Larry: depende se ele é feito com bom gosto, ou para o valor de choque: D
Matt Ellen
@ Matt: então, há um bom uso de variáveis ​​públicas?
Larry Coleman
@ Larry: (não eufemisticamente) ao alterar o estado do objeto, fora do controle do objeto, não fará com que o objeto esteja em um estado inválido. Eu acho que eventos em c # contam a esse respeito.
Matt Ellen
0

Um uso típico é conceder acesso a funções que fazem parte da interface da classe, mas graças a outras regras não podemos realmente fazer parte da classe. Inserters / extratores para iostreams são um exemplo clássico:

namespace whatever { 
    class something { 
        // ...    
        friend std::ostream &operator<<(std::ostream &os, something const &thing);
        friend std::istream &operator>>(std::istream &is, something &thing);
    };
}

Tornar esses operadores membros da classe não funcionará. Uma operação de E / S se parece com:

whatever::something thing;

std::cout << thing;

Para um operador implementado como uma função membro, isso seria resolvido como:

std::cout.operator<<(thing);

Ou seja, a função teria que ser membro de std::cout, não de something. Como não queremos modificar std::ostreamconstantemente, nossa única opção razoável é sobrecarregar o operador com uma função livre em vez de uma função membro. Isso nos deixa com duas possibilidades: ignorar completamente o encapsulamento e tornar público tudo na classe, ou mantê-lo privado, mas conceder acesso às poucas coisas que realmente precisam dele.

Tornar outra classe amiga é um pouco menos comum. Nesse caso, você normalmente cria algo da ordem de um módulo ou subsistema - um conjunto de classes que trabalham juntos e têm algum grau de acesso especial um ao outro que não é concedido ao mundo em geral.

Jerry Coffin
fonte
0

Há um bom exemplo da necessidade de classes de amigos nesta solicitação de classes semelhantes a amigos em C # , um idioma que não as possui.

Atacado citado aqui:

Os modificadores de acesso no .NET foram projetados com a idéia de que você pode confiar em seus colegas de trabalho para saber como o código funciona e, portanto, não escorregar e apresentar um bug.

Essa idéia é falha, no entanto. O desenvolvimento de software é tão complicado que um programador experiente sabe nem confiar em si mesmo! Por esse motivo, programadores experientes preferem escrever código que, por design, não pode ser quebrado por uso indevido acidental. O .NET fornece as ferramentas para fazer isso quando apenas uma classe está envolvida, mas no momento em que um programador tenta criar um conjunto à prova de balas de duas ou três classes interativas, isso ocorre.

A abordagem pretendida pelo .NET para isso é marcar os membros compartilhados como "internos", o que permite que as classes interajam com os internos uns dos outros. Infelizmente, isso também permite que todas as outras classes da assembléia mexam com os internos, seja por acidente ou intencionalmente.

Mads Torgersen, PM do idioma C #, chegou a responder a essa proposta, afirmando que a preocupação é realmente válida, mas não tem certeza da implementação específica sugerida lá.

O C ++ friendé apenas uma das maneiras de resolver o problema descrito.

enverpex
fonte
0

Quando você deseja que suas aulas tenham relacionamentos monogâmicos.

Por exemplo, quando você não deseja que classes desconhecidas acessem suas partes privadas, mas seus parceiros precisam de acesso.

Danny Varod
fonte
Casos de uso semelhantes aos internos em C # e pacote em Java.
Danny Varod
0

Eu achei as classes de amigo em C ++ úteis quando em Java eu ​​teria usado o acesso ao pacote. Ou seja, eu tenho um monte de classes que estão tão intimamente relacionadas que são escritas e mantidas como uma unidade, no (s) mesmo (s) arquivo (s) de origem. Quem trabalha em um deles está realmente trabalhando em todos eles. Os invariantes que eles mantêm, mantêm juntos. Faz sentido para eles ver os internos um do outro para que eles possam manter sua invariável compartilhada.

O que não faz sentido é o acesso protegido. Se não é seguro expor parte de meus internos ao público, não é seguro expô-lo a quaisquer jackanapes que surgem mais tarde em um projeto completamente não relacionado e afirme ser minha subclasse. Deixe as subclasses usarem minha interface pública, assim como todos os outros. (A menos que sejam amigos, mas nesse caso eu os escrevi e os implementei na mesma fonte, portanto, dificilmente são de outro projeto.)

ganbustein
fonte
-1

Vamos dizer que existe uma função externa que requer que você execute operações em membros privados ou protegidos de duas classes diferentes dentro do seu programa. agora, para que essa função tenha acesso e utilize esses membros da classe, você deve torná-la amiga das duas classes. Tendo em mente que, ao torná-lo amigo de ambas as classes, ele não é um membro das classes, apenas ganha a prevalência de se referir aos membros privados ou protegidos dessas classes. Posso dizer que você precisaria usar uma função de amigo quando quiser operar em objetos de duas classes diferentes. Embora o uso excessivo da função e classe do amigo possa reduzir o valor do encapsulamento.

Fiko V
fonte
2
é difícil ler este post (parede de texto). Você se importaria de editá -lo em uma forma melhor?
Gnat #