Справочное руководство по C++

R.11.4 Друзья.

Другом класса называется функция, которая не является членом класса, но в которой можно использовать частные и защищенные члены этого класса. Имя друга не принадлежит области видимости класса, и дружественная функция не вызывается с помощью операций доступа к членам (§R.5.2.4), если только она не является членом другого класса. Следующий пример показывает различие между членами и друзьями:

Class X {

 int a;

 friend void friend_set(X*, int);

Public:

 void member_set(int);

};

Void friend_set(X* p, int i) {p-›a = i;}.

Void X::member_set(int i) {a = i;}.

Void f().

{

 X obj;

 friend_set(&obj,10);

 obj.member_set(10);

}

Если в описании friend использовано имя перегруженной функции или операции, только функция, однозначно определяемая типами формальных параметров, становится другом. Функция-член класса X может быть другом класса Y, например:

Class Y {

 friend char* X::foo(int);

 //…

};

Можно объявить все функции класса X друзьями класса Y с помощью спецификации-сложного-типа (§R.9.1):

Class Y {

 friend class X;

 //…

};

Описание одного класса как друг другого класса дополнительно подразумевает, что частные и защищенные члены класса, предлагающего дружбу, могут использоваться в классе, получающем ее, например:

Class X {

 enum { a=100 };

 friend class Y;

};

Class Y {

 int v[X::a]; // Y друг класса X.

};

Class Z {

 int v[X::a]; // ошибка: X::a недоступно.

};

Если класс или функция, объявленные как друзья, не были описаны, их имена попадают в ту же область видимости, что и имя класса, содержащего описание friend (§R.9.1).

Функция, появившаяся первый раз в описании friend, считается эквивалентной функции, описанной как extern (§R.3.3, §R.7.1.1).

Если функция-друг определена в описании класса, она считается функцией со спецификацией inline и к ней применимо правило переноса определения функции для функций-членов (§R.9.3.2). Функция-друг, определенная в описании класса, относится на лексическом уровне к области видимости этого класса. Для функции-друга, определенной вне класса, это не так.

На описание friend не влияет указание спецификаций-доступа (§R.9.2).

Понятие дружбы не является ни наследуемым, ни транзитивным.

Подтвердим это примером:

Class A {

 friend class B;

 int a;

};

Class B {

 friend class C;

};

Class C {

 void f(A* p);

 {

  p-›a++; // ошибка: C не друг класса A, хотя.

   // является другом друга класса A.

 }

};

Class D: public B {

 void f(A* p).

 {

  p-›a++; // ошибка: D не друг класса A, хотя.

   // является производным друга класса A.

 }

};