FAQ Lite
Friends

[ 14.1 ] O que é uma [função ou classe] friend?
[ 14.2 ] Funções friends violam o encapsulamento?
[ 14.3 ] Quais são algumas vantagens/desvantagens de se usar funções friend?
[ 14.4 ] O que dignifica dizer friends não são herdáveis nem transitivas?
[ 14.5 ] Minha classe deve declarar uma função membro ou uma função friend?

[ 14.1 ] O que é uma [função ou classe] friend ?

Um recurso que permite que sua classe libere acesso a outra classe ou função.

Friends podem ser tanto outras classes quanto outras funções. Uma classe libera privilégios de acesso para as suas classes ou funções Frieds. Normalmente o desenvolvedor tem controle técnico e político tanto sobre friend quanto sobre funções membro da classe (a menos que você precise de permissão dos proprietários de outras peças do software para atualizar sua própria classe).

Topo
[ 14.2 ] Funções friends violam o encapsulamento?

Se forem usadas adequadamente, elas, na realidade, melhoram o encapsulamento.

Você freqüentemente precisa repartir uma classe ao meio, quando as duas metades têm diferentes números de instâncias, ou tem instâncias de diferentes durações (escopo). Nesses casos, as duas metades usualmente precisam de acessar uma a outra (as duas metades formam uma única classe, portanto você não aumentou o código que precisa de acesso direto a estrutura de dados; você simplesmente distribuiu o código em duas classes, ao invés de concentrá-lo em uma única classe). O modo seguro de implementar essa solução é fazer as duas classes friends uma da outra.

Se você usa friends exatamente dessa forma, você manterá os itens private como private. As pessoas que não entendem isso geralmente fazem um esforço, grande e ingênuo, de codificação para evitar usar friends em situações como a apresentada acima, e acabam, na realidade, por destruir o encapsulamento. Essas pessoas ou usam dados public (grotesco!), ou tornam os dados acessíveis a ambas as metades da classe via funções membro do tipo puclic get() e set(). Ter funções membro public get() e set() para dados private faz sentido apenas quando são usadas fora da classe (de um ponto de vista do usuário da classe). Em muitos casos, essas funções membro get() e set() são quase um mal uso de dados public: elas ocultam apenas os nomes dos  dados private, não ocultam sua existência.

Do mesmo modo, se você usa funções friend como uma variante sintática de funções de acesso aos itens public: da classe, elas não violam o encapsulamento mais do que uma função membro qualquer. Em outras palavras, classes e funções friends não violam a barreira do encapsulamento: assim com as funções membro da classe, elas são a barreira do encapsulamento.

Topo
[ 14.3 ] Quais são algumas vantagens/desvantagens de se usar funções  friend ?

Elas proporcionam um nível de liberdade entre as opções de projeto de interface das classes.

Funções membro e funções friend são igualmente privilegiadas (comprovadamente). A principal diferença é que uma função friend é chamada como f(x), enquando funções membro são chamadas como x.f(). Assim, a possibilidade de escolher entre funções membro ( x.f() ) e funções friend
(
f(x) ) permite ao projetista escojher a sintaxe que julgar mais legível e com menores custos de manutenção.

A principal desvantagem das funções friend é que elas requerem uma linha extra de código quando você quer ligação dinâmica. Para obter esse efeito em uma função virtual friend, a função friend deve chamar uma função membro virtual oculta, geralmente protected:. Esse mecanismo é chamado de Virtual Friend Idiom. Por exemplo:

    class Base {
    public:
      friend void f(Base& b);
      // ...
    protected:
      virtual void do_f();
      // ...
    };
    
    inline void f(Base& b)
    {
      b.do_f();
    }
    
    class Derived : public Base {
    public:
      // ...
    protected:
      virtual void do_f();  // "Override" the behavior of f(Base& b)
      // ...
    };
    
    void userCode(Base& b)
    {
      f(b);
    } 
O comando f(b) em userCode(Base&) vai invocar b.do_f(), que é virtual. Isso significa que Derived::do_f() vai obter o controle se b for na realidade uma class Derived. Note que Derived impõe-se sobre o comportamento da função membro protected: virtual d_f(); ela não tem sua própria variação da função friend f(Base&) 
Topo
[ 14.4 ] O que dignifica dizer friends não são herdáveis nem transitivas?

Eu posso declarar que sou seu amigo, mas isso não significa que eu, necessariamente, acredite que seus filhos, ou seus outros amigos, sejam meus amigos.
  • Eu não acredito, necessariamente, que seus filhos sejam meus amigos. Os privilégios da amizade não são herdáveis. Classes derivadas de classes friend não são necessariamente classes friends. Se a class Fred declara que class base é uma friend, as classes derivadas de Base não tem, automaticamente, direitos privilegiados de acesso aos objetos Fred
  • Eu não acredito, necessariamente, que seus outros amigos sejam meus amigos. Os privilégios da amizade não são transitivos. Um amigo de uma amigo não é necessariamente um amigo. Se a class Fred declara class Vilma como uma friend, e class Vilma declara class Betty como uma friend, class Bety não tem necessariamente qualquer direito especial de acesso aos objetos Fred.
Topo
[ 14.5 ] Minha classe deve declarar uma função membro ou uma função friend ?

Use funções membro quando puder, e friend quando for obrigado.

Algumas vezes friends são sintaticamente melhores (p.e., na class Fred, funções friend permitem que o parâmetro Fred seja o segundo, enquanto que funções membro requerem que seja o primeiro. Outro bom uso de funções friend são os operadores aritméticos binários fixos. P. e. aComplex + aComplex deveria ser definido como uma friend, ao invés de uma função membro, se você quer permitir aFloat + aComplex (uma função membro não permite a promoção do argumento da esquerda, uma vez que isso altera a classe do objeto que é o recipiente da invocação da função membro).

Em outros casos, prefira funções membro ao invés de friend.

Topo Anterior Próximo Índice
C++ FAQ Lite
Copyright © 1991-98 by Marshall Cline Ph.D., cline@parashift.com
Tradução: Dagoberto Haele Arnaut

| Home | Bookmarks | Universidades | Para Saber mais | Universidades | WEB Directory | Mapa do site |