Стандарт C++ 11 (1119564), страница 72
Текст из файла (страница 72)
∗/ };Here B is a public base of D2, D4, and D6, a private base of D1, D3, and D5, and a protected base of D7 andD8. — end example ]3[ Note: A member of a private base class might be inaccessible as an inherited member name, but accessibledirectly. Because of the rules on pointer conversions (4.10) and explicit casts (5.4), a conversion froma pointer to a derived class to a pointer to an inaccessible base class might be ill-formed if an implicitconversion is used, but well-formed if an explicit cast is used. For example,class B {public:int mi;static int si;};class D : private B {};class DD : public D {void f();};void DD::f() {mi = 3;si = 3;::B b;b.mi = 3;b.si = 3;::B::si = 3;::B* bp1 = this;::B* bp2 = (::B*)this;// non-static member// static member// error: mi is private in D// error: si is private in D//////////OK ( b.mi is different from this->mi)OK ( b.si is different from this->si)OKerror: B is a private base classOK with cast114) As specified previously in Clause 11, private members of a base class remain inaccessible even to derived classes unlessfriend declarations within the base class definition are used to grant access explicitly.§ 11.2© ISO/IEC 2011 – All rights reserved249ISO/IEC 14882:2011(E)bp2->mi = 3;// OK: access through a pointer to B.}— end note ]4A base class B of N is accessible at R, if— an invented public member of B would be a public member of N, or— R occurs in a member or friend of class N, and an invented public member of B would be a private orprotected member of N, or— R occurs in a member or friend of a class P derived from N, and an invented public member of B wouldbe a private or protected member of P, or— there exists a class S such that B is a base class of S accessible at R and S is a base class of N accessibleat R.[ Example: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 conditionabove: B is a base class of N accessible in f() becauseB is an accessible base class of S and S is an accessiblebase class of N.— end example ]5If a base class is accessible, one can implicitly convert a pointer to a derived class to a pointer to that baseclass (4.10, 4.11).
[ Note: It follows that members and friends of a class X can implicitly convert an X* to apointer to a private or protected immediate base class of X. — end note ] The access to a member is affectedby the class in which the member is named. This naming class is the class in which the member name waslooked up and found. [ Note: This class can be explicit, e.g., when a qualified-id is used, or implicit, e.g.,when a class member access operator (5.2.5) is used (including cases where an implicit “this->” is added).If both a class member access operator and a qualified-id are used to name the member (as in p->T::m), theclass naming the member is the class denoted by the nested-name-specifier of the qualified-id (that is, T).— end note ] A member m is accessible at the point R when named in class N if— m as a member of N is public, or— m as a member of N is private, and R occurs in a member or friend of class N, or— m as a member of N is protected, and R occurs in a member or friend of class N, or in a member orfriend of a class P derived from N, where m as a member of P is public, private, or protected, or§ 11.2250© ISO/IEC 2011 – All rights reservedISO/IEC 14882:2011(E)— there exists a base class B of N that is accessible at R, and m is accessible at R when named in class B.[ Example: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 ]6If a class member access operator, including an implicit “this->,” is used to access a non-static data memberor 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 naming class of the right operand.[ Note: This requirement is in addition to the requirement that the member be accessible as named.
— endnote ]11.31Friends[class.friend]A friend of a class is a function or class that is given permission to use the private and protected membernames from the class. A class specifies its friends, if any, by way of friend declarations. Such declarations givespecial access rights to the friends, but they do not make the nominated friends members of the befriendingclass.
[ Example: 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 ]2Declaring a class to be a friend implies that the names of private and protected members from the classgranting friendship can be accessed in the base-specifiers and member declarations of the befriended class.[ Example:class A {class B { };friend class X;};§ 11.3© ISO/IEC 2011 – All rights reserved251ISO/IEC 14882:2011(E)struct X : A::B {A::B mx;class Y {A::B my;};};// OK: A::B accessible to friend// OK: A::B accessible to member of friend// OK: A::B accessible to nested member of friend— end example ] [ Example:class X {enum { a=100 };friend class Y;};class Y {int v[X::a];};// OK, Y is a friend of Xclass Z {int v[X::a];};// error: X::a is private— end example ]A class shall not be defined in a friend declaration.
[ Example:class A {friend class B { }; // error: cannot define class in friend declaration};— end example ]3A friend declaration that does not declare a function shall have one of the following forms:friend elaborated-type-specifier ;friend simple-type-specifier ;friend typename-specifier ;[ Note: A friend declaration may be the declaration in a template-declaration (Clause 14, 14.5.4). — endnote ] If the type specifier in a friend declaration designates a (possibly cv-qualified) class type, that classis declared as a friend; otherwise, the friend declaration is ignored.
[ Example:class C;typedef C Ct;class X1 {friend C;};// OK: class C is a friendclass X2friendfriendfriend};// OK: class C is a friend// error: no type-name D in scope// OK: elaborated-type-specifier declares new class{Ct;D;class D;template <typename T> class R {friend T;§ 11.3252© ISO/IEC 2011 – All rights reservedISO/IEC 14882:2011(E)};R<C> rc;R<int> Ri;// class C is a friend of R<C>// OK: "friend int;" is ignored— end example ]4A function first declared in a friend declaration has external linkage (3.5).
Otherwise, the function retainsits previous linkage (7.1.1).5When a friend declaration refers to an overloaded name or operator, only the function specified by theparameter types becomes a friend. A member function of a class X can be a friend of a class Y.
[ Example:class Y {friend char* X::foo(int);friend X::X(char);friend X::~X();};// constructors can be friends// destructors can be friends— end example ]6A function can be defined in a friend declaration of a class if and only if the class is a non-local class (9.8),the function name is unqualified, and the function has namespace scope.
[ Example:class M {friend void f() { }// definition of global f, a friend of M,// not the definition of a member function};— end example ]7Such a function is implicitly inline. A friend function defined in a class is in the (lexical) scope of theclass in which it is defined. A friend function defined outside the class is not (3.4.1).8No storage-class-specifier shall appear in the decl-specifier-seq of a friend declaration.9A name nominated by a friend declaration shall be accessible in the scope of the class containing the frienddeclaration.
The meaning of the friend declaration is the same whether the friend declaration appears inthe private, protected or public (9.2) portion of the class member-specification.10Friendship is neither inherited nor transitive. [ Example: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}};§ 11.3© ISO/IEC 2011 – All rights reserved253ISO/IEC 14882:2011(E)class D : public Bvoid f(A* p) {p->a++;{// error: D is not a friend of A// despite being derived from a friend}};— end example ]11If a friend declaration appears in a local class (9.8) and the name specified is an unqualified name, a priordeclaration is looked up without considering scopes that are outside the innermost enclosing non-class scope.For a friend function declaration, if there is no prior declaration, the program is ill-formed. For a friend classdeclaration, if there is no prior declaration, the class that is specified belongs to the innermost enclosingnon-class scope, but if it is subsequently referenced, its name is not found by name lookup until a matchingdeclaration is provided in the innermost enclosing nonclass scope.
[ Example:class X;void a();void f() {class Y;extern void b();class A {friend class X;friend class Y;friend class Z;friend void a();friend void b();friend void c();};X *px;Z *pz;}////////////OK, but X is a local class, not ::XOKOK, introduces local class Zerror, ::a is not consideredOKerror// OK, but ::X is found// error, no Z is found— end example ]11.41Protected member access[class.protected]An additional access check beyond those described earlier in Clause 11 is applied when a non-static datamember or non-static member function is a protected member of its naming class (11.2)115 As describedearlier, access to a protected member is granted because the reference occurs in a friend or member of someclass C.
If the access is to form a pointer to member (5.3.1), the nested-name-specifier shall denote C or aclass derived from C. All other accesses involve a (possibly implicit) object expression (5.2.5). In this case,the class of the object expression shall be C or a class derived from C. [ Example:class B {protected:int i;static int j;};class D1 : public B {};class D2 : public B {115) This additional check does not apply to other members, e.g., static data members or enumerator member constants.§ 11.4254© ISO/IEC 2011 – All rights reservedISO/IEC 14882:2011(E)friend void fr(B*,D1*,D2*);void mem(B*,D1*);};void fr(B* pb, D1* p1, D2* p2) {pb->i = 1;//p1->i = 2;//p2->i = 3;//p2->B::i = 4;////int B::* pmi_B = &B::i;//int B::* pmi_B2 = &D2::i;//B::j = 5;//D2::j = 6;//}ill-formedill-formedOK (access through a D2)OK (access through a D2, even thoughnaming class is B)ill-formedOK (type of &D2::i is int B::*)OK (because refers to static member)OK (because refers to static member)void D2::mem(B* pb, D1* p1) {pb->i = 1;p1->i = 2;i = 3;B::i = 4;int B::* pmi_B = &B::i;int B::* pmi_B2 = &D2::i;j = 5;B::j = 6;}ill-formedill-formedOK (access through this)OK (access through this, qualification ignored)ill-formedOKOK (because j refers to static member)OK (because B::j refers to static member)void g(B*pb->i =p1->i =p2->i =}////////////////pb, D1* p1, D2* p2) {1;// ill-formed2;// ill-formed3;// ill-formed— end example ]11.51Access to virtual functions[class.access.virt]The access rules (Clause 11) for a virtual function are determined by its declaration and are not affected bythe rules for a function that later overrides it.