C ++ para amigo ou não para amigo

19

Eu tenho uma programação orientada a objetos com o curso c ++ neste semestre na faculdade e estávamos aprendendo sobre funções de amigos.

Eu os detesto instintivamente por sua capacidade de ignorar a segurança que o encapsulamento e a ocultação de dados fornecem, li alguns artigos na internet e algumas pessoas pensaram que era uma boa idéia com alguns usos legítimos.

O que um especialista em OOPs diria sobre as funções de amigos em C ++? Devo apenas dar uma olhada nele ou devo aprender mais sobre isso?

Nikhil
fonte
@ all: Respostas e comentários impressionantes, esta é uma ótima maneira de aprender, não há como eu ter aprendido sobre amigos em detalhes em um livro.
Nikhil

Respostas:

13

Nem sempre é conveniente criar todas as funções relacionadas aos membros de uma classe C ++ dessa classe. Por exemplo, imagine uma implementação de álgebra vetorial com multiplicação escalar. Queremos escrever:

 double a;
 Vector v, w;
 w = v * a;

Podemos fazer isso com uma função de membro:

public class Vector {
 ...
 Vector operator*(double a);
}

Mas também gostaríamos de escrever:

w = a * v

Isso requer uma função livre:

 Vector operator*(double a, Vector v)

A friendpalavra-chave foi adicionada ao C ++ para oferecer suporte a esse uso. A função free faz parte da implementação da classe Vector e deve ser declarada no mesmo cabeçalho e implementada no mesmo arquivo de origem.

Da mesma forma, podemos usar friendpara simplificar a implementação de classes fortemente acopladas, como uma coleção e um iterador. Novamente, eu declararia as duas classes no mesmo cabeçalho e as implementaria no mesmo arquivo de origem.

Kevin Cline
fonte
3
"Isso requer uma função livre". Não, não faz: inline Vector operator*(double a, Vector v) { return v*a; }. Solução canônica de fato.
precisa saber é o seguinte
1
@MSalters: Bom ponto. Eu escolhi um exemplo ruim. Eu acho que sua função embutida é uma função livre por definição, mas nenhuma declaração de amigo é necessária.
Kevin cline
4
@ MSalters: Isso é válido apenas se * for comutativo em relação a a e v (x). Se os componentes do vetor são genéricos (não necessariamente escalares) você tem que manter a ordem operando
Emilio Garavaglia
Isso é bastante teórico. Talvez o único caso não comutativo comum seja inline Vector operator*(double a, Vector v) { return -v*a; }e ainda não exija amizade.
MSalters
16

As funções de amigo não são diferentes das funções de membro em termos de encapsulamento. Eles podem, no entanto, oferecer outras vantagens, como serem mais genéricos, especialmente no que diz respeito aos modelos. Além disso, alguns operadores podem ser especificados apenas como funções livres; portanto, se você deseja que eles tenham acesso de membro, é necessário friend.

É melhor para frienduma única função do que ser forçado a fazer algo que você não quer que seja público. Isso significa que o mundo inteiro pode usá-lo - em vez de apenas uma função.

DeadMG
fonte
As funções +1 para Amigo não são diferentes das funções membro em termos de encapsulamento. Isso vale apenas para funções públicas de membros.
TheFogger
1
@ TheFogger: Pode-se argumentar que você também pode ter frienduma função "privada", como declarada apenas em uma única TU.
DeadMG
5

Se você é apaixonado pelo que faz, aprenderia tudo sobre C ++. Aprenda para que são usados, como usá-los e depois - e somente então - decida não usá-los. No mínimo, você estará preparado ao ler o código de outra pessoa que usa essa faceta do C ++.

JK
fonte
5

" O que diria um especialista em OOPs ... " Depende principalmente de como ele é especialista em C ++, que - por sua própria especificação - não é (e não quer ser) uma linguagem para puristas.

OOP Os fanáticos não usam C ++ (eles preferem Smalltalk e gostam de Java).

Os zelots de programação funcional não usam C ++ (eles preferem LISP e seus sucessores)

A maioria dos especialistas em OOP não gosta da função de amigos simplesmente porque deseja que a parte OOP do C ++ se comporte como Smalltalk. Mas o C ++ não é Smalltalk, e eles nem conseguem entender que um amigo não quebra o encapsulamento , pela simples razão de que uma função não pode ser amiga da sua classe sem que ela queira .

E do ponto de vista da "funcionalidade", entre a.fn(b)e fn(a,b)não há diferença (onde fnestá um amigo): as partes envolvidas são as mesmas. Simplesmente, uma sintaxe pode ser mais adequada que outra: se fn é comutativo em relação a ae b, fn(a,b)provavelmente , é mais adequado a.fn(b)(onde uma aparência tem um "papel especial" que, de fato, não é).

Emilio Garavaglia
fonte
1
Os "fanáticos por OOP" que gostam de Java não entenderam OOP. Getters? Setters? Não existe uma sintaxe simples para fechamentos? Parafraseando Alan Kay, não foi assim que ele imaginou OOP.
Konrad Rudolph
@ Konrad: fanáticos são um conjunto superiormente ilimitado. Sempre existe um fanático mais fanático do que um determinado fanático.
Emilio Garavaglia
Devo dizer que votei porque gostei muito do último parágrafo. Faz muito sentido.
precisa saber é
5

"Amigo" viola o encapsulamento?

Não, não tem. "Amigo" é um mecanismo explícito para conceder acesso, assim como a associação. Você não pode (em um programa em conformidade padrão) conceder a si mesmo acesso a uma classe sem modificar sua fonte.

fredoverflow
fonte
2

O FAQ do C ++ é sucinto:

Use um membro quando puder e um amigo quando for necessário.

O FAQ apresenta uma das maneiras mais úteis de pensar em amizade:

Muitas pessoas pensam que um amigo funciona como algo fora da classe. Em vez disso, tente pensar na função de um amigo como parte da interface pública da classe. Uma função de amigo na declaração de classe não viola o encapsulamento, assim como uma função de membro pública viola o encapsulamento: ambos têm exatamente a mesma autoridade em relação ao acesso às partes não públicas da classe.

Talvez o uso mais comum das funções de amigo esteja sobrecarregando << para E / S.

Gnawme
fonte
0

As funções de amigo são mais usadas para definições de operador definidas pelo usuário. Eles são úteis em outras situações, mas se você especificar classes de amigos com frequência, poderá estar em um desvio de design (apenas uma boa auto-verificação para usar ao escrever código).

Tenha cuidado com a declaração de "segurança" na pergunta original. Existem modificadores de acesso para impedir que você escreva códigos incorretos por acidente, assim como o compilador. Os modificadores de acesso limitam a interface e servem para comunicar quais funções são importantes para usar a classe (pública e protegida) e quais foram criadas como parte de tornar a classe mais bonita para os mantenedores (privados). Os modificadores não constituem segurança, pois existem muitas maneiras de obter dados privados. Por exemplo, pegue um ponteiro para a classe e seu tamanho e vá pescar.

anon
fonte
-2

As funções de amigo do C ++ estão intimamente relacionadas à seguinte funcionalidade:

  1. funções livres
  2. funções estáticas
  3. funções de amigo

Isso significa que eles não possuem esse ponteiro e, portanto, estão fora da classe / objeto. Por outro lado, eles geralmente usam parâmetros que os fazem novamente pertencer à classe. Aqui está um exemplo que esclarece o link:

class B;
class A {
public:
    friend void f(A &a, B &b);
private:
    int m_a;
};
class B {
public:
   friend void f(A &a, B &b);
private:
   int m_b;
};
void f(A &a, B &b) { /* uses both A's and B's private data */ }

A única diferença entre funções estáticas e funções de amigo é que uma função de amigo pode usar várias classes.

O uso do mecanismo friend em c ++ requer programadores com cerca de 10 a 15 anos de experiência com a maneira de programação em c ++ e, portanto, inicialmente você deve evitá-lo. É um recurso avançado.

tp1
fonte
7
E você derivou 10-15 anos como?
DeadMG
10-15 anos vem do momento em que ele se torna realmente necessário.
tp1
3
Então você arbitrariamente criou um número, então.
DeadMG
3
-1: "Você deve evitá-lo." Todos os recursos do C ++ foram criados para resolver um problema. Quando esse problema surgir, use o recurso apropriado.
Kevin cline
Obrigado pelo -1. Havia uma razão para esse comentário. Acho que é apenas um conceito difícil que nem todos os recursos são adequados para iniciantes.
tp1 5/09/11