Files
cppdraft_translate/cppdraft/class/friend.md
2025-10-25 03:02:53 +03:00

168 lines
8.0 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[class.friend]
# 11 Classes [[class]](./#class)
## 11.8 Member access control [[class.access]](class.access#class.friend)
### 11.8.4 Friends [class.friend]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4916)
A friend of a class is a function or class that is
given permission to name the private and protected members of the class[.](#1.sentence-1)
A class specifies its friends, if any, by way of friend declarations[.](#1.sentence-2)
Such declarations give special access rights to the friends, but they
do not make the nominated friends members of the befriending class[.](#1.sentence-3)
[*Example [1](#example-1)*:
The following example illustrates the differences between
members and friends: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);}
— *end example*]
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4946)
Declaring a class to be a friend implies that private and
protected members of the class granting friendship can be named in the[*base-specifier*](class.derived.general#nt:base-specifier "11.7.1General[class.derived.general]")*s* and member declarations of the befriended
class[.](#2.sentence-1)
[*Example [2](#example-2)*: class A {class B { }; friend class X;};
struct X : A::B { // OK, A::B accessible to friend A::B mx; // OK, A::B accessible to member of friendclass Y { A::B my; // OK, A::B accessible to nested member of friend};}; — *end example*]
[*Example [3](#example-3)*: class X {enum { a=100 }; friend class Y;};
class Y {int v[X::a]; // OK, Y is a friend of X};
class Z {int v[X::a]; // error: X::a is private}; — *end example*]
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4984)
A friend declaration that does not declare a function
shall be a [*friend-type-declaration*](class.mem.general#nt:friend-type-declaration "11.4.1General[class.mem.general]")[.](#3.sentence-1)
[*Note [1](#note-1)*:
A friend declaration can be the[*declaration*](dcl.pre#nt:declaration "9.1Preamble[dcl.pre]") in
a [*template-declaration*](temp.pre#nt:template-declaration "13.1Preamble[temp.pre]") ([[temp.pre]](temp.pre "13.1Preamble"), [[temp.friend]](temp.friend "13.7.5Friends"))[.](#3.sentence-2)
— *end note*]
If a [*friend-type-specifier*](class.mem.general#nt:friend-type-specifier "11.4.1General[class.mem.general]") in a friend declaration
designates a (possibly
cv-qualified) class type, that class is declared as a friend; otherwise, the[*friend-type-specifier*](class.mem.general#nt:friend-type-specifier "11.4.1General[class.mem.general]") is ignored[.](#3.sentence-3)
[*Example [4](#example-4)*: class C;typedef C Ct;class E;
class X1 {friend C; // OK, class C is a friend};
class X2 {friend Ct; // OK, class C is a friendfriend D; // error: D not foundfriend class D; // OK, elaborated-type-specifier declares new class};
template <typename ... Ts> class R {friend Ts...;};
template <class... Ts, class... Us>class R<R<Ts...>, R<Us...>> {friend Ts::Nested..., Us...;};
R<C> rc; // class C is a friend of R<C> R<C, E> rce; // classes C and E are friends of R<C, E> R<int> Ri; // OK, “friend int;'' is ignoredstruct E { struct Nested; };
R<R<E>, R<C, int>> rr; // E::Nested and C are friends of R<R<E>, R<C, int>> — *end example*]
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5032)
[*Note [2](#note-2)*:
A friend declaration refers to an entity, not (all overloads of) a name[.](#4.sentence-1)
A member function of a classX can be a friend of
a classY[.](#4.sentence-2)
[*Example [5](#example-5)*: class Y {friend char* X::foo(int); friend X::X(char); // constructors can be friendsfriend X::~X(); // destructors can be friends}; — *end example*]
— *end note*]
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5053)
A function may be defined in a friend declaration of a class if and only if the
class is a non-local class ([[class.local]](class.local "11.6Local class declarations")) and the function name is unqualified[.](#5.sentence-1)
[*Example [6](#example-6)*: class M {friend void f() { } // definition of global f, a friend of M,// not the definition of a member function}; — *end example*]
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5066)
Such a function is implicitly an inline ([[dcl.inline]](dcl.inline "9.2.8The inline specifier")) function
if it is attached to the global module[.](#6.sentence-1)
[*Note [3](#note-3)*:
If a friend function is defined outside a class,
it is not in the scope of the class[.](#6.sentence-2)
— *end note*]
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5074)
No[*storage-class-specifier*](dcl.stc#nt:storage-class-specifier "9.2.2Storage class specifiers[dcl.stc]") shall appear in the[*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") of a friend declaration[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5081)
A member nominated by a friend declaration shall be accessible in the
class containing the friend declaration[.](#8.sentence-1)
The meaning of the friend declaration is the same whether the friend declaration
appears in the private, protected, or public ([[class.mem]](class.mem "11.4Class members"))
portion of the class[*member-specification*](class.mem.general#nt:member-specification "11.4.1General[class.mem.general]")[.](#8.sentence-2)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5090)
Friendship is neither inherited nor transitive[.](#9.sentence-1)
[*Example [7](#example-7)*: class A {friend class B; int a;};
class B {friend class C;};
class C {void f(A* p) { p->a++; // error: C is not a friend of A despite being a friend of a friend}};
class D : public B {void f(A* p) { p->a++; // error: D is not a friend of A despite being derived from a friend}}; — *end example*]
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5118)
[*Note [4](#note-4)*:
A friend declaration never binds any names ([[dcl.meaning]](dcl.meaning "9.3.4Meaning of declarators"), [[dcl.type.elab]](dcl.type.elab "9.2.9.5Elaborated type specifiers"))[.](#10.sentence-1)
— *end note*]
[*Example [8](#example-8)*: // Assume f and g have not yet been declared.void h(int);template <class T> void f2(T);namespace A {class X {friend void f(X); // A::f(X) is a friendclass Y {friend void g(); // A::g is a friendfriend void h(int); // A::h is a friend// ::h not consideredfriend void f2<>(int); // ::f2<>(int) is a friend}; }; // A::f, A::g and A::h are not visible here X x; void g() { f(x); } // definition of A::gvoid f(X) { /* ... */ } // definition of A::fvoid h(int) { /* ... */ } // definition of A::h// A::f, A::g and A::h are visible here and known to be friends}using A::x;
void h() { A::f(x);
A::X::f(x); // error: f is not a member of A::X A::X::Y::g(); // error: g is not a member of A::X::Y} — *end example*]
[*Example [9](#example-9)*: class X;void a();void f() {class Y; extern void b(); class A {friend class X; // OK, but X is a local class, not ::Xfriend class Y; // OKfriend class Z; // OK, introduces local class Zfriend void a(); // error, ::a is not consideredfriend void b(); // OKfriend void c(); // error};
X* px; // OK, but ::X is found Z* pz; // error: no Z is found} — *end example*]