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

}

};