Friends (C++ only)

A friend of a class X is a function or class that is not a member of X, but is granted the same access to X as the members of X. Functions declared with the friend specifier in a class member list are called friend functions of that class. Classes declared with the friend specifier in the member list of another class are called friend classes of that class.

A class Y must be defined before any member of Y can be declared a friend of another class. In the following example, the friend function print is a member of class Y and accesses the private data members a and b of class X.

#include <iostream>
using namespace std;

class X;

class Y {
public:
  void print(X& x);
};

class X {
  int a, b;
  friend void Y::print(X& x);
public:
  X() : a(1), b(2) { }
};

void Y::print(X& x) {
  cout << "a is " << x.a << endl;
  cout << "b is " << x.b << endl;
}

int main() {
  X xobj;
  Y yobj;
  yobj.print(xobj);
}
See the output of the above example:
a is 1
b is 2

You can declare an entire class as a friend. Suppose class F is a friend of class A. This means that every member function and static data member definition of class F has access to class A.

In the following example, the friend class F has a member function print that accesses the private data members a and b of class X and performs the same task as the friend function print in the above example. Any other members declared in class F also have access to all members of class X.

#include <iostream>
using namespace std;

class X {
  int a, b;
  friend class F;    
public:
  X() : a(1), b(2) { }
};

class F {
public:
  void print(X& x) {
    cout << "a is " << x.a << endl;
    cout << "b is " << x.b << endl;
  }
};

int main() {
  X xobj;
  F fobj;
  fobj.print(xobj);
}
See the output of the above example:
a is 1
b is 2
You cannot define a class in a friend declaration. For example, the compiler does not accept the following code:
class F;
class X {
  friend class F { };
};
However, you can define a function in a friend declaration. The class must be a non-local class. The function must have namespace scope, and the function name must be unqualified. The following example demonstrates this:
class A {
  void g();
};

void z() {
  class B {
    friend void f() { }; // error
  };
}

class C {
  friend void A::g() { } // error
  friend void h() { }
};
The compiler accepts the definition of h(), but not the function definition of f() or g().

You cannot declare a friend with a storage class specifier.

C++11

Extended friend declarations

Note: IBM supports selected features of C++11, known as C++0x before its ratification. IBM will continue to develop and implement the features of this standard. The implementation of the language level is based on IBM's interpretation of the standard. Until IBM's implementation of all the C++11 features is complete, including the support of a new C++11 standard library, the implementation may change from release to release. IBM makes no attempt to maintain compatibility, in source, binary, or listings and other compiler interfaces, with earlier releases of IBM's implementation of the new C++11 features.
In the C++11 standard, the extended friend declarations feature accepts additional forms of non-function friend declarations.
Note: The syntactic form of extended friend declarations overlaps with the IBM old friend declaration syntax. This section is focused on the differences between the C++11 standard and the previous ISO C++ standard.
With this feature enabled, the class-key is no longer required in the context of friend declarations. This new syntax differs from the C++98 friend class declaration syntax, where the class-key is necessary as part of an elaborated-type-specifier. See the following example:
class F;
class G;

class X1 {
  //C++98 friend declarations remain valid in C++11.
  friend class F;
 
  //Error in C++98 for missing the class-key.
  friend G;
};

class X2 {
  //Error in C++98 for missing the class-key.
  //Error in C++11 for lookup failure (no previous class D declaration).
  friend D;
  
  friend class D;
};
In addition to functions and classes, you can also declare template parameters and basic types as friends. In this case, you cannot use an elaborated-type-specifier in the friend declaration. In the following example, you can declare the template parameter T as a friend of class F, and you can use the basic type char in friend declarations.
class C;

template <typename T, typename U> class F {
   //C++11 compiles sucessfully. 
   //Error in C++98 for missing the class-key. 
   friend T;
   
   //Error in both C++98 and C++11: a template parameter
   //must not be used in an elaborated type specifier.
   friend class U;

};   

F<C> rc;
F<char> Ri;
You can also declare typedef names as friends, but you still cannot use an elaborated-type-specifier in the friend declaration. The following example demonstrates that the typedef name D is declared as a friend of class Base.
class Derived;
typedef Derived D;

class C;
typedef C Ct; 

class Base{
public:
   Base() : x(55) {}

   //C++11 compiles sucessfully.
   //Error in C++98 for missing the class-key.
   friend D; 

   //Error in both C++98 and C++11: a typedef name 
   //must not be used in an elaborated type specifier.
   friend class Ct;

private:
   int x;
};
 
struct Derived : public Base {
   int foo() { return this->x; }
};

int main() {
   Derived d;
   return d.foo();
}
This feature also introduces a new name lookup rule for friend declarations. If a friend class declaration does not use an elaborated-type-specifier, then the compiler also looks for the entity name in scopes outside the innermost namespace that encloses the friend declaration. Consider the following example:
struct T { }; 

namespace N {
   struct A {
      friend T;  
   }; 
}
In this example, if this feature is in effect, the friend declaration statement does not declare a new entity T, but looks for T. If there is no T found, then the compiler issues an error. Consider another example:
struct T { }; 

namespace N {
   struct A { 
        friend class T;  //fine, no error
   };
} 
In this example, the friend declaration statement does not look for T outside namespace N, nor does it find ::T. Instead, this statement declares a new class T in namespace N.
End C++11