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);
}
The following is 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);
}
The following is 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++0x

Extended friend declarations

Note: C++0x is a new version of the C++ programming language standard. This is a draft standard and has not been officially adopted in its entirety. The implementation of C++0x is based on IBM's interpretation of the draft C++0x standard and is subject to change at any time without notice. IBM makes no attempt to maintain compatibility with earlier releases and therefore the C++0x language extension should not be relied on as a stable programming interface.
In the C++0x 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++0x 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++0x.
  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++0x 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++0x compiles sucessfully. 
   //Error in C++98 for missing the class-key. 
   friend T;
   
   //Error in both C++98 and C++0x: 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++0x compiles sucessfully.
   //Error in C++98 for missing the class-key.
   friend D; 

   //Error in both C++98 and C++0x: 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++0x