|
|
Другом класса называется функция, которая не является членом класса, но в которой можно использовать частные и защищенные члены этого класса. Имя друга не принадлежит области видимости класса, и дружественная функция не вызывается с помощью операций доступа к членам ($$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 } };
| |