Compartir a través de


friend (C++)

En algunas circunstancias, es útil que una clase conceda acceso de nivel de miembro a funciones que no son miembros de la clase o a todos los miembros de una clase independiente. Estas funciones y clases gratuitas se conocen como friends, marcados por la palabra clave friend. Solo el implementador de la clase puede declarar cuáles son sus funciones o clases friend. Las funciones o clases no pueden hacerlo por sí mismas. En una definición de clase, use la palabra clave friend y el nombre de una función no miembro u otra clase para conceder acceso a los miembros privados y protegidos de la clase. En una definición de plantilla, un parámetro de tipo se puede declarar como friend.

Sintaxis

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

Declaraciones friend

Si declara una función friend que no se declaró previamente, esa función se exporta al ámbito de inclusión que no es de clase.

Las funciones declaradas en una declaración friend se tratan como si se hubieran declarado mediante la palabra clave extern. Para obtener más información, vea extern.

Aunque las funciones con ámbito global se pueden declarar como friend antes que los prototipos, las funciones miembro no se pueden declarar como friend antes de que aparezca la declaración de clase completa. En el código siguiente se muestra cómo se produce un error en esta declaración:

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

El ejemplo anterior introduce el nombre de clase ForwardDeclared en el ámbito, pero la declaración completa (específicamente, la parte que declara la función IsAFriend) no se conoce. Por consiguiente, la declaración de friend en la clase HasFriends genera un error.

En C++11, hay dos formas de declaraciones "friend" para una clase:

friend class F;
friend F;

El primer formulario introduce una nueva clase F si no se encontró ninguna clase existente por ese nombre en el espacio de nombres más interno. C++11: el segundo formulario no presenta una nueva clase; se puede usar cuando la clase ya se ha declarado y debe usarse al declarar un parámetro de tipo de plantilla typedef como un friend.

Use friend class F cuando el tipo al que se hace referencia aún no se haya declarado:

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

Se produce un error si usa friend con un tipo de clase que no se ha declarado:

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

En el ejemplo siguiente, friend F hace referencia a la clase F que se declara fuera del ámbito de NS.

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

Use friend F para declarar un parámetro de plantilla como friend:

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

Use friend F para declarar una definición de tipo como friend:

class Foo {};
typedef Foo F;

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

Para declarar dos clases que son de tipo friend entre sí, la segunda clase completa se debe especificar como friend de la primera clase. La razón de esta restricción se debe a que el compilador solo tiene información suficiente para declarar funciones friend individuales en el punto donde se declara la segunda clase.

Nota:

Aunque la segunda clase completa debe ser definirse como friend en la primera clase, puede seleccionar las funciones de la primera clase que se definen como friend para la segunda clase.

funciones de confianza

Una función friend es una función que no es miembro de una clase pero tiene acceso a los miembros privados y protegidos de la clase. Las funciones friend no se consideran miembros de clase; son funciones externas normales que tienen privilegios de acceso especiales. No están en el ámbito de la clase y no se las llama usando los operadores de selección de miembro (. y >) a menos que sean miembros de otra clase. Una función friend la declara la clase que concede el acceso. La declaración friend se puede colocar en cualquier lugar de la declaración de clase. No se ve afectada por las palabras clave de control de acceso.

En el ejemplo siguiente se muestra una clase Point y una función friend, ChangePrivate. La función friend tiene acceso al miembro de datos privado del objeto Point que recibe como 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
}

Miembros de clase como friend

Las funciones miembro de clase se pueden declarar como de confianza en otras clases. Considere el ejemplo siguiente:

// 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

En el ejemplo anterior, solo se concede a la función A::Func1( B& ) acceso friend a la clase B. Por consiguiente, el acceso al miembro privado _b es correcto en Func1 de la clase A pero no en Func2.

Una clase friend es una clase todas cuyas funciones miembro con funciones friend de una clase, es decir, cuyas funciones miembro tienen acceso a los miembros privados y protegidos de la otra clase. Suponga que la declaración friend de la clase B hubiera sido:

friend class A;

En ese caso, a todas las funciones miembro de la clase A se les habría concedido acceso friend a la clase B. El código siguiente es un ejemplo de una clase 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();
}

La declaración "friend" no es mutua a menos que se especifique explícitamente como tal. En el ejemplo anterior, las funciones miembro de YourClass no pueden tener acceso a los miembros privados de YourOtherClass.

Un tipo administrado (en C++/CLI) no puede tener funciones friend, clases friend ni interfaces friend.

La declaración "friend" no se hereda, lo que significa que las clases derivadas de YourOtherClass no pueden tener acceso a los miembros privados de YourClass. La declaración "friend" no es transitiva, por lo que las clases friend de YourOtherClass no pueden tener acceso a los miembros privados de YourClass.

La ilustración siguiente muestra cuatro declaraciones de clase: Base, Derived, aFriend y anotherFriend. Solo la clase aFriend tiene acceso directo a los miembros privados de Base (y a cualquier miembro Base que pueda haber heredado).

Diagrama que muestra las implicaciones de derivación de una relación de confianza.

El diagrama muestra que la clase anotherFriend no tiene una relación de amistad con la clase base que es amiga de la clase aFriend. La clase aFriend es amiga de la clase base, pero no tiene una relación de amistad con la clase derivada a pesar de que la clase derivada hereda de la clase base. Esto demuestra que la herencia no implica que la clase derivada tenga los mismos amigos que la clase base.

Definición friend insertadas

Las funciones friend se pueden definir (dado un cuerpo de función) dentro de las declaraciones de clase. Estas funciones son funciones insertadas. Como funciones insertadas de miembro, se comportan como si se hubieran definido inmediatamente después de haberse considerado todos los miembros de clase pero antes de cerrarse el ámbito de clase (el final de la declaración de clase). Las funciones friend definidas dentro de declaraciones de clase están en el ámbito de la clase envolvente.

Consulte también

Palabras clave