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);
}
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);
}
a is 1
b is 2
class F;
class G;
class X {
friend class F;
friend G;
};
The compiler will warn you that the friend declaration of G
must
be an elaborated class name.
class F;
class X {
friend class F { };
};
class A {
void g();
};
void z() {
class B {
// friend void f() { };
};
}
class C {
// friend void A::g() { }
friend void h() { }
};
The compiler would not allow the function definition
of f()
or g()
. The compiler will
allow the definition of h()
.You cannot declare a friend with a storage class specifier.
Beginning of C++0x only.
Extended friend declarations
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;
};
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 of C++0x only.