______________________________________________________________________ 11 Member access control [class.access] ______________________________________________________________________ 1 A member of a class can be --private; that is, its name can be used only by member functions, static data members, and friends of the class in which it is declared. --protected; that is, its name can be used only by member functions, static data members, and friends of the class in which it is declared and by member functions, static data members, and friends of classes derived from this class (see _class.protected_). --public; that is, its name can be used anywhere without access restriction. 2 Members of a class defined with the keyword class are private by default. Members of a class defined with the keywords struct or union are public by default. [Example: class X { int a; // X::a is private by default }; struct S { int a; // S::a is public by default }; --end example] 3 Access control is applied uniformly to all names. In the case of overloaded function names, access control is applied to the function selected by overload resolution. [Note: because access control applies to names, if access control is applied to a typedef name, only the accessibility of the typedef name itself is considered. The accessibility of the entity referred to by the typedef is not consid ered. For example, class A { class B { }; public: typedef B BB; }; void f() { A::BB x; // ok, typedef name A::BB is public A::B y; // access error, A::B is private } --end note] 4 It should be noted that it is access to members and base classes that is controlled, not their visibility. Names of members are still visi ble, and implicit conversions to base classes are still considered, when those members and base classes are inaccessible. The interpreta tion of a given construct is established without regard to access con trol. If the interpretation established makes use of inaccessible member names or base classes, the construct is ill-formed. 5 All access controls in this clause affect the ability to access a class member name from a particular scope. In particular, access con trols apply as usual to member names accessed as part of a function return type, even though it is not possible to determine the access privileges of that use without first parsing the rest of the function. [Example: class A { typedef int I; // private member I f(); friend I g(I); static I x; }; A::I A::f() { return 0; } A::I g(A::I); A::I g(A::I p) { return 0; } A::I A::x = 0; Here, all the uses of A::I are well-formed because A::f and A::x are members of class A and g is a friend of class A. This implies, for example, that access checking on the first use of A::I must be deferred until it is determined that this use of A::I is as the return type of a member of class A. --end example] 6 It is necessary to name a class member to define it outside of the definition of its class. For this reason, no access checking is per formed on the components of the qualified-id used to name the member in the declarator of such a definition. [Example: class D { class E { static int m; }; }; int D::E::m = 1; // Okay, no access error on private `E' --end example] 11.1 Access specifiers [class.access.spec] 1 Member declarations can be labeled by an access-specifier (_class.derived_): access-specifier : member-specificationopt An access-specifier specifies the access rules for members following it until the end of the class or until another access-specifier is encountered. [Example: class X { int a; // X::a is private by default: `class' used public: int b; // X::b is public int c; // X::c is public }; --end example] Any number of access specifiers is allowed and no par ticular order is required. [Example: struct S { int a; // S::a is public by default: `struct' used protected: int b; // S::b is protected private: int c; // S::c is private public: int d; // S::d is public }; --end example] 2 The order of allocation of data members with separate access-specifier labels is unspecified (_class.mem_). 3 When a member is redeclared within its class definition, the access specified at its redeclaration shall be the same as at its initial declaration. [Example: struct S { class A; private: class A { }; // error: cannot change access }; --end example] 11.2 Access specifiers for base classes [class.access.base] 1 If a class is declared to be a base class (_class.derived_) for another class using the public 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. If a class is declared to be a base class for another class using the protected access specifier, the pub lic and protected members of the base class are accessible as pro tected members of the derived class. If a class is declared to be a base class for another class using the private access specifier, the public and protected members of the base class are accessible as pri vate members of the derived class1). _________________________ 1) As specified previously in _class.access_, private members of a 2 In the absence of an access-specifier for a base class, public is assumed when the derived class is declared struct and private is assumed when the class is declared class. [Example: class B { /* ... */ }; class D1 : private B { /* ... */ }; class D2 : public B { /* ... */ }; class D3 : B { /* ... */ }; // `B' private by default struct D4 : public B { /* ... */ }; struct D5 : private B { /* ... */ }; struct D6 : B { /* ... */ }; // `B' public by default class D7 : protected B { /* ... */ }; struct D8 : protected B { /* ... */ }; 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 and D8. --end example] 3 [Note: A member of a private base class might be inaccessible as an inherited member name, but accessible directly. Because of the rules on pointer conversions (_conv.ptr_) and explicit casts (_expr.cast_), a conversion from a pointer to a derived class to a pointer to an inaccessible base class might be ill-formed if an implicit conversion is used, but well-formed if an explicit cast is used. For example, class B { public: int mi; // nonstatic member static 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; // okay (b.mi is different from this->mi) b.si = 3; // okay (b.si is different from this->si) B::si = 3; // okay B* bp1 = this; // error: B is a private base class B* bp2 = (B*)this; // okay with cast bp2->mi = 3; // okay: access through a pointer to B. } --end note] 4 A base class is said to be accessible if an invented public member of the base class is accessible. 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.mem_). [Note: It follows that members _________________________ base class remain inaccessible even to derived classes unless friend declarations within the base class declaration are used to grant ac cess explicitly. and friends of a class X can implicitly convert an X* to a pointer to a private or protected immediate base class of X. ] 11.3 Access declarations [class.access.dcl] 1 The access of a member of a base class can be changed in the derived class by mentioning its qualified-id in the derived class declaration. Such mention is called an access declaration. The base class member is given, in the derived class, the access in effect in the derived class declaration at the point of the access declaration. The effect of an access declaration qualified-id ; is defined to be equivalent to the declaration using qualified-id ;.2) 2 [Example: class A { public: int z; int z1; }; class B : public A { int a; public: int b, c; int bf(); protected: int x; int y; }; class D : private B { int d; public: B::c; // adjust access to `B::c' B::z; // adjust access to `A::z' A::z1; // adjust access to `A::z1' int e; int df(); protected: B::x; // adjust access to `B::x' int g; }; _________________________ 2) Access declarations are deprecated; member using-declarations (_namespace.udecl_) provide a better means of doing the same things. In earlier versions of the C++ language, access declarations were more limited; they were generalized and made equivalent to using- declarations in the interest of simplicity. Programmers are encour aged to use using, rather than the new capabilities of access declara tions, in new code. class X : public D { int xf(); }; int ef(D&); int ff(X&); The external function ef can use only the names c, z, z1, e, and df. Being a member of D, the function df can use the names b, c, z, z1, bf, x, y, d, e, df, and g, but not a. Being a member of B, the func tion bf can use the members a, b, c, z, z1, bf, x, and y. The func tion xf can use the public and protected names from D, that is, c, z, z1, e, and df (public), and x, and g (protected). Thus the external function ff has access only to c, z, z1, e, and df. If D were a pro tected or private base class of X, xf would have the same privileges as before, but ff would have no access at all. ] 11.4 Friends [class.friend] 1 A friend of a class is a function or class that is not a member of the class but is permitted to use the private and protected member names from the class. The name of a friend is not in the scope of the class, and the friend is not called with the member access operators (_expr.ref_) unless it is a member of another class. [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] 2 When a friend declaration refers to an overloaded name or operator, only the function specified by the parameter types becomes a friend. A member function of a class X can be a friend of a class Y. [Exam ple: class Y { friend char* X::foo(int); // ... }; --end example] Declaring a class to be a friend implies that private and protected names from the class granting friendship can be accessed in declarations of members of the befriended class. An elaborated- type-specifier shall be used in a friend declaration for a class; see _dcl.type.elab_ .3) [Note: _dcl.type.elab_ further describes the syn tax of friend class declarations. ] [Example: 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] Access to private and protected names is also granted to member functions of the friend class (as if the functions were each friends) and to the static data member definitions of the friend class. 3 [Note: _basic.scope.pdecl_ describes the point of declaration of a class name or a function name first introduced by a friend declara tion. ] 4 A function first declared in a friend declaration has external linkage (_basic.link_). Otherwise, it retains its previous linkage (_dcl.stc_). No storage-class-specifier shall appear in the decl- specifier-seq of a friend declaration. 5 A function can be defined in a friend declaration of a class if and only if the class is a non-local class (_class.local_), 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] Such a function is implicitly inline. A friend func tion defined in a class is in the (lexical) scope of the class in which it is defined. A friend function defined outside the class is not (_basic.lookup.unqual_). 6 Friend declarations are not affected by access-specifiers (_class.mem_). 7 Friendship is neither inherited nor transitive. [Example: class A { friend class B; int a; }; class B { friend class C; }; _________________________ 3) The class-key of the elaborated-type-specifier is required. 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] 11.5 Protected member access [class.protected] 1 When a friend or a member function of a derived class references a protected nonstatic member of a base class, an access check applies in addition to those described earlier in this clause.4) Except when forming a pointer to member (_expr.unary.op_), the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class) (_expr.ref_). If the access is to form a pointer to member, the nested-name-specifier shall name the derived class (or any class derived from that class). [Exam ple: 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*); }; _________________________ 4) This additional check does not apply to other members, e.g. static data members. void fr(B* pb, D1* p1, D2* p2) { pb->i = 1; // ill-formed p1->i = 2; // ill-formed p2->i = 3; // ok (access through a D2) p2->B::i = 4; // ok (access through a D2, qualification ignored) int B::* pmi_B = &B::i; // ill-formed int B::* pmi_B2 = &D2::i; // ok (type of &D2::i is "int B::*") B::j = 5; // ok (because refers to static member) D2::j =6; // ok (because refers to static member) } void D2::mem(B* pb, D1* p1) { pb->i = 1; // ill-formed p1->i = 2; // ill-formed i = 3; // ok (access through `this') B::i = 4; // ok (access through `this', qualification ignored) j = 5; // ok (because refers to static member) B::j = 6; // ok (because refers to static member) } void g(B* pb, D1* p1, D2* p2) { pb->i = 1; // ill-formed p1->i = 2; // ill-formed p2->i = 3; // ill-formed } --end example] 11.6 Access to virtual functions [class.access.virt] 1 The access rules (_class.access_) for a virtual function are deter mined by its declaration and are not affected by the rules for a func tion that later overrides it. [Example: 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] 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). The access of the member func tion in the class in which it was defined (D in the example above) is in general not known. 11.7 Multiple access [class.paths] 1 If a name can be reached by several paths through a multiple inheri tance graph, the access is that of the path that gives most access. [Example: 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 }; Since W::f() is available to C::f() along the public path through B, access is allowed. ]