friend (C++)

Em algumas circunstâncias, é útil que uma classe conceda acesso ao nível de membro a funções que não são membros da classe ou a todos os membros em uma classe separada. Essas funções e classes gratuitas são conhecidas como amigas, marcadas pela palavra-chave friend. Somente o implementador de classe pode declarar quem são seus amigos. Uma função ou classe não pode se declarar como amiga de nenhuma classe. Em uma definição de classe, use a palavra-chave e o nome de uma função não membro ou outra classe para conceder a friend ela acesso aos membros privados e protegidos de sua classe. Em uma definição de modelo, um parâmetro de tipo pode ser declarado como um friend.

Sintaxe

friend-declaration:
friend function-declaration
friend function-definition
friendelaborated-type-specifier;;
friend simple-type-specifier ;
friend typename-specifier ;

Declarações friend

Se você declarar uma função friend que não tenha sido declarada anteriormente, essa função será exportada para o escopo de envolvimento sem classe.

As funções declaradas em uma declaração friend são tratadas como se tivessem sido declaradas usando a palavra-chave extern. Para obter mais informações, consulte extern.

Ainda que as funções com escopo global possam ser declaradas como friend antes dos protótipos, as funções de membro não podem ser declaradas como friend antes de aparecer a declaração completa de sua classe. O código a seguir mostra como essa declaração falha:

class ForwardDeclared;   // Class name is known.
class HasFriends
{
    friend int ForwardDeclared::IsAFriend();   // C2039 error expected
};

O exemplo anterior insere o nome da classe ForwardDeclared no escopo, mas a declaração completa (especificamente, a parte que declara a função IsAFriend) não é conhecida. a declaração friend na classe HasFriends gera um erro.

No C++11, há dois formulários de declarações de amigos para uma classe:

friend class F;
friend F;

O primeiro formulário introduz uma nova classe F, caso nenhuma classe existente por esse nome seja encontrada no namespace mais interno. C++11: o segundo formulário não introduz uma nova classe; ele pode ser usado quando a classe já foi declarada e deve ser usada ao declarar um parâmetro de tipo de modelo ou um typedef como um friend.

Use friend class F quando o tipo referenciado ainda não tiver sido declarado:

namespace NS
{
    class M
    {
        friend class F;  // Introduces F but doesn't define it
    };
}

Ocorrerá um erro se você usar friend com um tipo de classe que não foi declarado:

namespace NS
{
    class M
    {
        friend F; // error C2433: 'NS::F': 'friend' not permitted on data declarations
    };
}

No exemplo a seguir, friend F refere-se à F classe declarada fora do escopo do NS.

class F {};
namespace NS
{
    class M
    {
        friend F;  // OK
    };
}

Use friend F para declarar um parâmetro de modelo como um amigo:

template <typename T>
class my_class
{
    friend T;
    //...
};

Use friend F para declarar um typedef como amigo:

class Foo {};
typedef Foo F;

class G
{
    friend F; // OK
    friend class F // Error C2371 -- redefinition
};

Para declarar duas classes que são amigas da outro, a segunda classe inteira deve ser especificada como amiga de primeira classe. A razão para essa restrição é que o compilador tem informações suficientes para declarar funções individuais de amigo somente no ponto onde a segunda classe é declarada.

Observação

Embora a segunda classe inteira deve ser amiga da primeira classe, você pode selecionar quais funções na primeira classe serão amigas da segunda classe.

funções friend

Uma função friend é uma função que não é membro de uma classe, mas que tem acesso a membros particulares e protegidos da classe. As funções friend não são consideradas membros de classe; elas são funções externas normais que recebem privilégios de acesso especiais. As funções amigo não estão no escopo da classe e não são chamadas usando os operadores da seleção de membro (. e –>) a menos que sejam membros de outra classe. Uma função friend é declarada pela classe que está concedendo acesso. A declaração friend pode ser colocada em qualquer lugar da declaração da classe. Ela não é afetada pelas palavras-chave de controle de acesso.

O exemplo a seguir mostra uma classe Point e uma função friend, ChangePrivate. A função friend tem acesso ao membro de dados particular do objeto Point que ela recebe como um parâmetro.

// friend_functions.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;
class Point
{
    friend void ChangePrivate( Point & );
public:
    Point( void ) : m_i(0) {}
    void PrintPrivate( void ){cout << m_i << endl; }

private:
    int m_i;
};

void ChangePrivate ( Point &i ) { i.m_i++; }

int main()
{
   Point sPoint;
   sPoint.PrintPrivate();
   ChangePrivate(sPoint);
   sPoint.PrintPrivate();
// Output: 0
           1
}

Membros da classe como amigos

As funções de membro da classe podem ser declaradas como amigos em outras classes. Considere o seguinte exemplo:

// classes_as_friends1.cpp
// compile with: /c
class B;

class A {
public:
   int Func1( B& b );

private:
   int Func2( B& b );
};

class B {
private:
   int _b;

   // A::Func1 is a friend function to class B
   // so A::Func1 has access to all members of B
   friend int A::Func1( B& );
};

int A::Func1( B& b ) { return b._b; }   // OK
int A::Func2( B& b ) { return b._b; }   // C2248

No exemplo anterior, somente a função A::Func1( B& ) tem acesso de friend para a classe B. Em virtude disso, o acesso ao membro particular _b está correto em Func1 da classe A, mas não em Func2.

Uma classe friend é uma classe cujas funções membro são as funções friend de uma classe, ou seja, cujas funções membro tenham acesso aos outros membros particulares e protegidos da classe. Suponha que a declaração friend na classe B fosse:

friend class A;

Nesse caso, todas as funções membro na classe A receberão acesso de friend para a classe B. O código a seguir é um exemplo de uma classe friend:

// classes_as_friends2.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;
class YourClass {
friend class YourOtherClass;  // Declare a friend class
public:
   YourClass() : topSecret(0){}
   void printMember() { cout << topSecret << endl; }
private:
   int topSecret;
};

class YourOtherClass {
public:
   void change( YourClass& yc, int x ){yc.topSecret = x;}
};

int main() {
   YourClass yc1;
   YourOtherClass yoc1;
   yc1.printMember();
   yoc1.change( yc1, 5 );
   yc1.printMember();
}

A amizade não é mútua a menos que explicitamente especificada como tal. No exemplo anterior, as funções membro de YourClass não podem acessar os membros privados de YourOtherClass.

Um tipo gerenciado (em C++/CLI) não pode ter nenhuma função friend, classes friend ou interfaces friend.

A amizade não é herdada, o que significa que as classes derivadas de YourOtherClass não podem acessar os membros particulares de YourClass. A amizade não é transitiva, assim as classes que são amigos de YourOtherClass não podem acessar membros particulares de YourClass.

A figura a seguir mostra quatro declarações de classe: Base, Derived, aFriend e anotherFriend. Somente a classe aFriend tem acesso direto aos membros privados de Base (e a todos os membros que Base pode ter herdado).

A diagram that shows the derivation implications of a friend relationship.

O diagrama mostra que a classe anotherFriend não tem uma relação de amizade com a base da classe que os amigos classe aFriend. A classe aFriend é amiga da classe Base, mas não tem uma relação de amizade com a classe Derivada, mesmo que a classe Derived herde da Base. Isso demonstra que a herança não implica que a classe derivada tenha os mesmos amigos que a classe base.

Definições friend embutidas

As funções friend podem ser definidas (dado um corpo de função) dentro de declarações de classe. Essas funções são funções embutidas. Como funções membro embutidas, elas se comportam como se fossem definidas imediatamente após todos os membros de classe terem sido vistos, mas antes que o escopo de classe seja fechado (no final da declaração de classe). As funções friend que são definidas dentro de declarações de classe estão no escopo da classe delimitadora.

Confira também

Palavras-chave