674 lines
33 KiB
Markdown
674 lines
33 KiB
Markdown
[class.access]
|
||
|
||
# 11 Classes [[class]](./#class)
|
||
|
||
## 11.8 Member access control [class.access]
|
||
|
||
### [11.8.1](#general) General [[class.access.general]](class.access.general)
|
||
|
||
[1](#general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4323)
|
||
|
||
A member of a class can be
|
||
|
||
- [(1.1)](#general-1.1)
|
||
|
||
private,
|
||
that is, it can be named only by members and friends
|
||
of the class in which it is declared;
|
||
|
||
- [(1.2)](#general-1.2)
|
||
|
||
protected,
|
||
that is, it can be named only by members and friends
|
||
of the class in which it is declared, by classes derived from that class, and by their
|
||
friends (see [[class.protected]](#class.protected "11.8.5 Protected member access")); or
|
||
|
||
- [(1.3)](#general-1.3)
|
||
|
||
public,
|
||
that is, it can be named anywhere without access restriction[.](#general-1.sentence-1)
|
||
|
||
[*Note [1](#general-note-1)*:
|
||
|
||
A constructor or destructor can be named by an expression ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule"))
|
||
even though it has no name[.](#general-1.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[2](#general-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4347)
|
||
|
||
A member of a class can also access all the members to which the class has access[.](#general-2.sentence-1)
|
||
|
||
A local class of a member function may access
|
||
the same members that the member function itself may access[.](#general-2.sentence-2)[96](#footnote-96 "Access permissions are thus transitive and cumulative to nested and local classes.")
|
||
|
||
[3](#general-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4357)
|
||
|
||
Members of a class defined with the keywordclass are private by default[.](#general-3.sentence-1)
|
||
|
||
Members of a class defined with the keywordsstruct or union are public by default[.](#general-3.sentence-2)
|
||
|
||
[*Example [1](#general-example-1)*: class X {int a; // X::a is private by default};
|
||
|
||
struct S {int a; // S::a is public by default}; â *end example*]
|
||
|
||
[4](#general-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4379)
|
||
|
||
Access control is applied uniformly to declarations and expressions[.](#general-4.sentence-1)
|
||
|
||
[*Note [2](#general-note-2)*:
|
||
|
||
Access control applies to members nominated by
|
||
friend declarations ([[class.friend]](#class.friend "11.8.4 Friends")) and[*using-declaration*](namespace.udecl#nt:using-declaration "9.10 The using declaration [namespace.udecl]")*s* ([[namespace.udecl]](namespace.udecl "9.10 The using declaration"))[.](#general-4.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
When a [*using-declarator*](namespace.udecl#nt:using-declarator "9.10 The using declaration [namespace.udecl]") is named,
|
||
access control is applied to it, not to the declarations that replace it[.](#general-4.sentence-3)
|
||
|
||
For an overload set, access control is applied only to
|
||
the function selected by overload resolution[.](#general-4.sentence-4)
|
||
|
||
[*Example [2](#general-example-2)*: struct S {void f(int);private:void f(double);};
|
||
|
||
void g(S* sp) { sp->f(2); // OK, access control applied after overload resolution} â *end example*]
|
||
|
||
[*Note [3](#general-note-3)*:
|
||
|
||
Because access control applies to the declarations named,
|
||
if access control is applied to a type alias,
|
||
only the accessibility of the typedef or alias declaration itself is considered[.](#general-4.sentence-5)
|
||
|
||
The accessibility of the underlying entity is not considered[.](#general-4.sentence-6)
|
||
|
||
[*Example [3](#general-example-3)*: class A {class B { };public:typedef B BB;};
|
||
|
||
void f() { A::BB x; // OK, typedef A::BB is public A::B y; // access error, A::B is private} â *end example*]
|
||
|
||
â *end note*]
|
||
|
||
[5](#general-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4424)
|
||
|
||
[*Note [4](#general-note-4)*:
|
||
|
||
Access control does not prevent members from being found by name lookup or
|
||
implicit conversions to base classes from being considered[.](#general-5.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
The interpretation of a given construct is
|
||
established without regard to access control[.](#general-5.sentence-2)
|
||
|
||
If the interpretation
|
||
established makes use of inaccessible members or base classes,
|
||
the construct is ill-formed[.](#general-5.sentence-3)
|
||
|
||
[6](#general-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4435)
|
||
|
||
All access controls in [class.access] affect the ability to name a class member
|
||
from the declaration of a particular
|
||
entity, including parts of the declaration preceding the name of the entity
|
||
being declared and, if the entity is a class, the definitions of members of
|
||
the class appearing outside the class's [*member-specification*](class.mem.general#nt:member-specification "11.4.1 General [class.mem.general]")[.](#general-6.sentence-1)
|
||
|
||
[*Note [5](#general-note-5)*:
|
||
|
||
This access also applies to implicit references to constructors,
|
||
conversion functions, and destructors[.](#general-6.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[7](#general-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4446)
|
||
|
||
[*Example [4](#general-example-4)*: class A {typedef int I; // private member I f() pre(A::x > 0); friend I g(I) post(A::x <= 0); static I x; template<int> struct Q; template<int> friend struct R;protected:struct B { };};
|
||
|
||
A::I A::f() pre(A::x > 0) { return 0; } A::I g(A::I p = A::x) post(A::x <= 0);
|
||
A::I g(A::I p) { return 0; } A::I A::x = 0;template<A::I> struct A::Q { };template<A::I> struct R { };
|
||
|
||
struct D: A::B, A { };
|
||
|
||
Here, all the uses ofA::I are well-formed becauseA::f,A::x, and A::Q are members of classA andg and R are friends of classA[.](#general-7.sentence-1)
|
||
|
||
This implies, for example, that access checking on the first use ofA::I must be deferred until it is determined that this use ofA::I is as the return type of a member of classA[.](#general-7.sentence-2)
|
||
|
||
Similarly, the use of A::B as a[*base-specifier*](class.derived.general#nt:base-specifier "11.7.1 General [class.derived.general]") is well-formed because D is derived from A, so checking of [*base-specifier*](class.derived.general#nt:base-specifier "11.7.1 General [class.derived.general]")*s* must be deferred until the entire [*base-specifier-list*](class.derived.general#nt:base-specifier-list "11.7.1 General [class.derived.general]") has been seen[.](#general-7.sentence-3)
|
||
|
||
â *end example*]
|
||
|
||
[8](#general-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4493)
|
||
|
||
Access is checked for a default argument ([[dcl.fct.default]](dcl.fct.default "9.3.4.7 Default arguments"))
|
||
at the point of declaration,
|
||
rather than at any points of use of the default argument[.](#general-8.sentence-1)
|
||
|
||
Access checking for default arguments in function templates and in
|
||
member functions of class templates is performed as described in [[temp.inst]](temp.inst "13.9.2 Implicit instantiation")[.](#general-8.sentence-2)
|
||
|
||
[9](#general-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4502)
|
||
|
||
Access for a default [*template-argument*](temp.names#nt:template-argument "13.3 Names of template specializations [temp.names]") ([[temp.param]](temp.param "13.2 Template parameters"))
|
||
is checked in the context in which it appears rather than at any
|
||
points of use of it[.](#general-9.sentence-1)
|
||
|
||
[*Example [5](#general-example-5)*: class B { };template <class T> class C {protected:typedef T TT;};
|
||
|
||
template <class U, class V = typename U::TT>class D : public U { };
|
||
|
||
D <C<B> >* d; // access error, C::TT is protected â *end example*]
|
||
|
||
[96)](#footnote-96)[96)](#footnoteref-96)
|
||
|
||
Access
|
||
permissions are thus transitive and cumulative to nested
|
||
and local classes[.](#footnote-96.sentence-1)
|
||
|
||
### [11.8.2](#spec) Access specifiers [[class.access.spec]](class.access.spec)
|
||
|
||
[1](#spec-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4524)
|
||
|
||
Member declarations can be labeled by an[*access-specifier*](class.derived.general#nt:access-specifier "11.7.1 General [class.derived.general]") ([[class.derived]](class.derived "11.7 Derived classes")):
|
||
|
||
[*access-specifier*](class.derived.general#nt:access-specifier "11.7.1 General [class.derived.general]") : [*member-specification*](class.mem.general#nt:member-specification "11.4.1 General [class.mem.general]")opt
|
||
|
||
An[*access-specifier*](class.derived.general#nt:access-specifier "11.7.1 General [class.derived.general]") specifies the access rules for members following it
|
||
until the end of the class or until another[*access-specifier*](class.derived.general#nt:access-specifier "11.7.1 General [class.derived.general]") is encountered[.](#spec-1.sentence-2)
|
||
|
||
[*Example [1](#spec-example-1)*: class X {int a; // X::a is private by default: class usedpublic:int b; // X::b is publicint c; // X::c is public}; â *end example*]
|
||
|
||
[2](#spec-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4549)
|
||
|
||
Any number of access specifiers is allowed and no particular order is required[.](#spec-2.sentence-1)
|
||
|
||
[*Example [2](#spec-example-2)*: struct S {int a; // S::a is public by default: struct usedprotected:int b; // S::b is protectedprivate:int c; // S::c is privatepublic:int d; // S::d is public}; â *end example*]
|
||
|
||
[3](#spec-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4565)
|
||
|
||
When a member is redeclared within its class definition,
|
||
the access specified at its redeclaration shall
|
||
be the same as at its initial declaration[.](#spec-3.sentence-1)
|
||
|
||
[*Example [3](#spec-example-3)*: struct S {class A; enum E : int;private:class A { }; // error: cannot change accessenum E: int { e0 }; // error: cannot change access}; â *end example*]
|
||
|
||
[4](#spec-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4581)
|
||
|
||
[*Note [1](#spec-note-1)*:
|
||
|
||
In a derived class, the lookup of a base class name will find the
|
||
injected-class-name instead of the name of the base class in the scope
|
||
in which it was declared[.](#spec-4.sentence-1)
|
||
|
||
The injected-class-name might be less accessible
|
||
than the name of the base class in the scope in which it was declared[.](#spec-4.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [4](#spec-example-4)*: class A { };class B : private A { };class C : public B { A* p; // error: injected-class-name A is inaccessible::A* q; // OK}; â *end example*]
|
||
|
||
### [11.8.3](#base) Accessibility of base classes and base class members [[class.access.base]](class.access.base)
|
||
|
||
[1](#base-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4607)
|
||
|
||
If a class is declared to be a base class ([[class.derived]](class.derived "11.7 Derived classes")) for another class using thepublic access specifier, the
|
||
public members of the base class are accessible as
|
||
public members of the derived class and
|
||
protected members of the base class are accessible as
|
||
protected members of the derived class[.](#base-1.sentence-1)
|
||
|
||
If a class is declared to be a base class for another class using theprotected access specifier, the
|
||
public and protected members of the base class are accessible as
|
||
protected members of the derived class[.](#base-1.sentence-2)
|
||
|
||
If a class is declared to be a base class for another class using theprivate access specifier, the
|
||
public and protected
|
||
members of the base class are accessible as private
|
||
members of the derived class[.](#base-1.sentence-3)[97](#footnote-97 "As specified previously in [class.access], private members of a base class remain inaccessible even to derived classes unless friend declarations within the base class definition are used to grant access explicitly.")
|
||
|
||
[2](#base-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4633)
|
||
|
||
In the absence of an[*access-specifier*](class.derived.general#nt:access-specifier "11.7.1 General [class.derived.general]") for a base class,public is assumed when the derived class is
|
||
defined with the [*class-key*](class.pre#nt:class-key "11.1 Preamble [class.pre]")struct andprivate is assumed when the class is
|
||
defined with the [*class-key*](class.pre#nt:class-key "11.1 Preamble [class.pre]")class[.](#base-2.sentence-1)
|
||
|
||
[*Example [1](#base-example-1)*: class B { /* ... */ };class D1 : private B { /* ... */ };class D2 : public B { /* ... */ };class D3 : B { /* ... */ }; // B private by defaultstruct D4 : public B { /* ... */ };struct D5 : private B { /* ... */ };struct D6 : B { /* ... */ }; // B public by defaultclass D7 : protected B { /* ... */ };struct D8 : protected B { /* ... */ };
|
||
|
||
HereB is a public base ofD2,D4,
|
||
andD6,
|
||
a private base ofD1,D3,
|
||
andD5,
|
||
and a protected base ofD7 andD8[.](#base-2.sentence-2)
|
||
|
||
â *end example*]
|
||
|
||
[3](#base-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4677)
|
||
|
||
[*Note [1](#base-note-1)*:
|
||
|
||
A member of a private base class can be inaccessible as inherited,
|
||
but accessible directly[.](#base-3.sentence-1)
|
||
|
||
Because of the rules on pointer conversions ([[conv.ptr]](conv.ptr "7.3.12 Pointer conversions")) and
|
||
explicit casts ([[expr.type.conv]](expr.type.conv "7.6.1.4 Explicit type conversion (functional notation)"), [[expr.static.cast]](expr.static.cast "7.6.1.9 Static cast"), [[expr.cast]](expr.cast "7.6.3 Explicit type conversion (cast notation)")),
|
||
a conversion from a pointer to a derived class to a pointer
|
||
to an inaccessible base class can be ill-formed if an implicit conversion
|
||
is used, but well-formed if an explicit cast is used[.](#base-3.sentence-2)
|
||
|
||
[*Example [2](#base-example-2)*: class B {public:int mi; // non-static memberstatic int si; // static member};class D : private B {};class DD : public D {void f();};
|
||
|
||
void DD::f() { mi = 3; // error: mi is private in D si = 3; // error: si is private in D::B b;
|
||
b.mi = 3; // OK (b.mi is different from this->mi) b.si = 3; // OK (b.si is different from this->si)::B::si = 3; // OK::B* bp1 = this; // error: B is a private base class::B* bp2 = (::B*)this; // OK with cast bp2->mi = 3; // OK, access through a pointer to B.} â *end example*]
|
||
|
||
â *end note*]
|
||
|
||
[4](#base-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4714)
|
||
|
||
A base classB ofN is[*accessible*](#def:accessible "11.8.3 Accessibility of base classes and base class members [class.access.base]") at*R*,
|
||
if
|
||
|
||
- [(4.1)](#base-4.1)
|
||
|
||
an invented public member ofB would be a public member ofN, or
|
||
|
||
- [(4.2)](#base-4.2)
|
||
|
||
*R* occurs in a direct member or friend of classN,
|
||
and an invented public member ofB would be a private or protected member ofN, or
|
||
|
||
- [(4.3)](#base-4.3)
|
||
|
||
*R* occurs in a direct member or friend of a classP derived fromN,
|
||
and an invented public member ofB would be a private or protected member ofP, or
|
||
|
||
- [(4.4)](#base-4.4)
|
||
|
||
there exists a classS such thatB is a base class ofS accessible at*R* andS is a base class ofN accessible at*R*[.](#base-4.sentence-1)
|
||
|
||
[*Example [3](#base-example-3)*: class B {public:int m;};
|
||
|
||
class S: private B {friend class N;};
|
||
|
||
class N: private S {void f() { B* p = this; // OK because class S satisfies the fourth condition above: B is a base class of N// accessible in f() because B is an accessible base class of S and S is an accessible// base class of N.}}; â *end example*]
|
||
|
||
[5](#base-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4786)
|
||
|
||
If a base class is accessible, one can implicitly convert a pointer to
|
||
a derived class to a pointer to that base class ([[conv.ptr]](conv.ptr "7.3.12 Pointer conversions"), [[conv.mem]](conv.mem "7.3.13 Pointer-to-member conversions"))[.](#base-5.sentence-1)
|
||
|
||
[*Note [2](#base-note-2)*:
|
||
|
||
It follows that
|
||
members and friends of a classX can implicitly convert anX* to a pointer to a private or protected immediate base class ofX[.](#base-5.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
An expression E that designates a member m has a [*designating class*](#def:class,designating "11.8.3 Accessibility of base classes and base class members [class.access.base]") that affects the access to m[.](#base-5.sentence-3)
|
||
|
||
This designating class is either
|
||
|
||
- [(5.1)](#base-5.1)
|
||
|
||
the innermost class of which m is directly a member
|
||
if E is a [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") or
|
||
|
||
- [(5.2)](#base-5.2)
|
||
|
||
the class in whose scope name lookup performed a search
|
||
that found m otherwise[.](#base-5.sentence-4)
|
||
|
||
[*Note [3](#base-note-3)*:
|
||
|
||
This class can be explicit, e.g., when a[*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") is used, or implicit, e.g., when a class member access operator ([[expr.ref]](expr.ref "7.6.1.5 Class member access")) is used (including cases where an implicit
|
||
âthis->â
|
||
is
|
||
added)[.](#base-5.sentence-5)
|
||
|
||
If both a class member access operator and a[*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") are used to name the member (as inp->T::m),
|
||
the class designating the member is the class designated by the[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") of the[*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") (that is,T)[.](#base-5.sentence-6)
|
||
|
||
â *end note*]
|
||
|
||
A memberm is accessible at the point*R* when designated in classN if
|
||
|
||
- [(5.3)](#base-5.3)
|
||
|
||
m is designated by a [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]"), or
|
||
|
||
- [(5.4)](#base-5.4)
|
||
|
||
m as a member ofN is public, or
|
||
|
||
- [(5.5)](#base-5.5)
|
||
|
||
m as a member ofN is private, and*R* occurs in a direct member or friend of classN,
|
||
or
|
||
|
||
- [(5.6)](#base-5.6)
|
||
|
||
m as a member ofN is protected, and*R* occurs in a direct member or friend of classN,
|
||
or in a member of a classP derived fromN,
|
||
wherem as a member ofP is public, private, or protected, or
|
||
|
||
- [(5.7)](#base-5.7)
|
||
|
||
there exists a base classB ofN that is accessible at*R*,
|
||
andm is accessible at*R* when designated in classB[.](#base-5.sentence-7)
|
||
[*Example [4](#base-example-4)*: class B;class A {private:int i; friend void f(B*);};class B : public A { };void f(B* p) { p->i = 1; // OK, B* can be implicitly converted to A*, and f has access to i in A} â *end example*]
|
||
|
||
[6](#base-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4898)
|
||
|
||
If a class member access operator, including an implicit
|
||
âthis->â,
|
||
is used to access a non-static data member or non-static
|
||
member function, the reference is ill-formed if the
|
||
left operand (considered as a pointer in the
|
||
â.â
|
||
operator case) cannot be implicitly converted to a
|
||
pointer to the designating class of the right operand[.](#base-6.sentence-1)
|
||
|
||
[*Note [4](#base-note-4)*:
|
||
|
||
This requirement is in addition to the requirement that
|
||
the member be accessible as designated[.](#base-6.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[97)](#footnote-97)[97)](#footnoteref-97)
|
||
|
||
As specified previously in [class.access],
|
||
private members of a base class remain inaccessible even to derived classes
|
||
unless friend
|
||
declarations within the base class definition are used to grant access explicitly[.](#footnote-97.sentence-1)
|
||
|
||
### [11.8.4](#class.friend) Friends [[class.friend]](class.friend)
|
||
|
||
[1](#class.friend-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[.](#class.friend-1.sentence-1)
|
||
|
||
A class specifies its friends, if any, by way of friend declarations[.](#class.friend-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[.](#class.friend-1.sentence-3)
|
||
|
||
[*Example [1](#class.friend-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](#class.friend-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.1 General [class.derived.general]")*s* and member declarations of the befriended
|
||
class[.](#class.friend-2.sentence-1)
|
||
|
||
[*Example [2](#class.friend-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](#class.friend-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](#class.friend-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.1 General [class.mem.general]")[.](#class.friend-3.sentence-1)
|
||
|
||
[*Note [1](#class.friend-note-1)*:
|
||
|
||
A friend declaration can be the[*declaration*](dcl.pre#nt:declaration "9.1 Preamble [dcl.pre]") in
|
||
a [*template-declaration*](temp.pre#nt:template-declaration "13.1 Preamble [temp.pre]") ([[temp.pre]](temp.pre "13.1 Preamble"), [[temp.friend]](temp.friend "13.7.5 Friends"))[.](#class.friend-3.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
If a [*friend-type-specifier*](class.mem.general#nt:friend-type-specifier "11.4.1 General [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.1 General [class.mem.general]") is ignored[.](#class.friend-3.sentence-3)
|
||
|
||
[*Example [4](#class.friend-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](#class.friend-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5032)
|
||
|
||
[*Note [2](#class.friend-note-2)*:
|
||
|
||
A friend declaration refers to an entity, not (all overloads of) a name[.](#class.friend-4.sentence-1)
|
||
|
||
A member function of a classX can be a friend of
|
||
a classY[.](#class.friend-4.sentence-2)
|
||
|
||
[*Example [5](#class.friend-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](#class.friend-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.6 Local class declarations")) and the function name is unqualified[.](#class.friend-5.sentence-1)
|
||
|
||
[*Example [6](#class.friend-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](#class.friend-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.8 The inline specifier")) function
|
||
if it is attached to the global module[.](#class.friend-6.sentence-1)
|
||
|
||
[*Note [3](#class.friend-note-3)*:
|
||
|
||
If a friend function is defined outside a class,
|
||
it is not in the scope of the class[.](#class.friend-6.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[7](#class.friend-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5074)
|
||
|
||
No[*storage-class-specifier*](dcl.stc#nt:storage-class-specifier "9.2.2 Storage class specifiers [dcl.stc]") shall appear in the[*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") of a friend declaration[.](#class.friend-7.sentence-1)
|
||
|
||
[8](#class.friend-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[.](#class.friend-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.4 Class members"))
|
||
portion of the class[*member-specification*](class.mem.general#nt:member-specification "11.4.1 General [class.mem.general]")[.](#class.friend-8.sentence-2)
|
||
|
||
[9](#class.friend-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5090)
|
||
|
||
Friendship is neither inherited nor transitive[.](#class.friend-9.sentence-1)
|
||
|
||
[*Example [7](#class.friend-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](#class.friend-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5118)
|
||
|
||
[*Note [4](#class.friend-note-4)*:
|
||
|
||
A friend declaration never binds any names ([[dcl.meaning]](dcl.meaning "9.3.4 Meaning of declarators"), [[dcl.type.elab]](dcl.type.elab "9.2.9.5 Elaborated type specifiers"))[.](#class.friend-10.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [8](#class.friend-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](#class.friend-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*]
|
||
|
||
### [11.8.5](#class.protected) Protected member access [[class.protected]](class.protected)
|
||
|
||
[1](#class.protected-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5181)
|
||
|
||
An additional access check beyond those described earlier in [class.access]
|
||
is applied when a non-static data member or non-static member function is a
|
||
protected member of its naming class ([[class.access.base]](#base "11.8.3 Accessibility of base classes and base class members"))[.](#class.protected-1.sentence-1)[98](#footnote-98 "This additional check does not apply to other members, e.g., static data members or enumerator member constants.")
|
||
|
||
As described earlier, access to a protected member is granted because the
|
||
reference occurs in a friend or direct member of some class C[.](#class.protected-1.sentence-2)
|
||
|
||
If the access is
|
||
to form a pointer to member ([[expr.unary.op]](expr.unary.op "7.6.2.2 Unary operators")), the[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") shall denote C or a class derived fromC[.](#class.protected-1.sentence-3)
|
||
|
||
All other accesses involve a (possibly implicit) object
|
||
expression ([[expr.ref]](expr.ref "7.6.1.5 Class member access"))[.](#class.protected-1.sentence-4)
|
||
|
||
In this case, the class of the object expression shall beC or a class derived from C[.](#class.protected-1.sentence-5)
|
||
|
||
[*Example [1](#class.protected-example-1)*: class B {protected:int i; static int j;};
|
||
|
||
class D1 : public B {};
|
||
|
||
class D2 : public B {friend void fr(B*,D1*,D2*); void mem(B*,D1*);};
|
||
|
||
void fr(B* pb, D1* p1, D2* p2) { pb->i = 1; // error p1->i = 2; // error p2->i = 3; // OK (access through a D2) p2->B::i = 4; // OK (access through a D2, even though naming class is B)int B::* pmi_B = &B::i; // errorint B::* pmi_B2 = &D2::i; // OK (type of &D2::i is int B::*) B::j = 5; // error: not a friend of naming class B D2::j = 6; // OK (because refers to static member)}void D2::mem(B* pb, D1* p1) { pb->i = 1; // error p1->i = 2; // error i = 3; // OK (access through this) B::i = 4; // OK (access through this, qualification ignored)int B::* pmi_B = &B::i; // errorint B::* pmi_B2 = &D2::i; // OK j = 5; // OK (because j refers to static member) B::j = 6; // OK (because B::j refers to static member)}void g(B* pb, D1* p1, D2* p2) { pb->i = 1; // error p1->i = 2; // error p2->i = 3; // error} â *end example*]
|
||
|
||
[98)](#footnote-98)[98)](#footnoteref-98)
|
||
|
||
This
|
||
additional check does not apply to other members,
|
||
e.g., static data members or enumerator member constants[.](#footnote-98.sentence-1)
|
||
|
||
### [11.8.6](#virt) Access to virtual functions [[class.access.virt]](class.access.virt)
|
||
|
||
[1](#virt-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5246)
|
||
|
||
The access rules ([class.access]) for a virtual function are determined by its declaration
|
||
and are not affected by the rules for a function that later overrides it[.](#virt-1.sentence-1)
|
||
|
||
[*Example [1](#virt-example-1)*: class B {public:virtual int f();};
|
||
|
||
class D : public B {private:int f();};
|
||
|
||
void f() { D d;
|
||
B* pb = &d;
|
||
D* pd = &d;
|
||
|
||
pb->f(); // OK, B::f() is public, D::f() is invoked pd->f(); // error: D::f() is private} â *end example*]
|
||
|
||
[2](#virt-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5272)
|
||
|
||
Access is checked at the call point using the type of the expression used
|
||
to denote the object for which the member function is called
|
||
(B* in the example above)[.](#virt-2.sentence-1)
|
||
|
||
The access of the member function in the class in which it was defined
|
||
(D in the example above) is in general not known[.](#virt-2.sentence-2)
|
||
|
||
### [11.8.7](#class.paths) Multiple access [[class.paths]](class.paths)
|
||
|
||
[1](#class.paths-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5284)
|
||
|
||
If a declaration can be reached by several paths through a multiple inheritance
|
||
graph, the access is that of the path that gives most access[.](#class.paths-1.sentence-1)
|
||
|
||
[*Example [1](#class.paths-example-1)*: class W { public: void f(); };class A : private virtual W { };class B : public virtual W { };class C : public A, public B {void f() { W::f(); } // OK};
|
||
|
||
SinceW::f() is available toC::f() along the public path throughB,
|
||
access is allowed[.](#class.paths-1.sentence-2)
|
||
|
||
â *end example*]
|
||
|
||
### [11.8.8](#nest) Nested classes [[class.access.nest]](class.access.nest)
|
||
|
||
[1](#nest-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5310)
|
||
|
||
A nested class is a member and as such has the same access rights as any other member[.](#nest-1.sentence-1)
|
||
|
||
The members of an enclosing class have no special access to members of a nested
|
||
class; the usual access rules ([class.access]) shall be obeyed[.](#nest-1.sentence-2)
|
||
|
||
[*Example [1](#nest-example-1)*: class E {int x; class B { }; class I { B b; // OK, E::I can access E::Bint y; void f(E* p, int i) { p->x = i; // OK, E::I can access E::x}}; int g(I* p) {return p->y; // error: I::y is private}}; â *end example*]
|