-1- A member of a class can be
-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 };
-3- Access control is applied uniformly to all names, whether the names are referred to from declarations or expressions. [Note: access control applies to names nominated by friend declarations (class.friend) and using-declarations (namespace.udecl). ] 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 considered. 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 }
-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 visible, and implicit conversions to base classes are still considered, when those members and base classes are inaccessible. The interpretation of a given construct is established without regard to access control. If the interpretation established makes use of inaccessible member names or base classes, the construct is ill-formed.
-5- All access controls in clause class.access affect the ability to access a class member name from a particular scope. The access control for names used in the definition of a class member that appears outside of the member's class definition is done as if the entire member definition appeared in the scope of the member's class. In particular, access controls 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 declarator. Similarly, access control for implicit calls to the constructors, the conversion functions, or the destructor called to create and destroy a static data member is performed as if these calls appeared in the scope of the member's class. [Example:
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. ]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 p = A::x); A::I g(A::I p) { return 0; } A::I A::x = 0;
-6- In the definition of a member of a nested class that appears outside of its class definition, the name of the member may be qualified by the names of enclosing classes of the member's class even if these names are private members of their enclosing classes. [Example:
class D { class E { static int m; }; }; int D::E::m = 1; //OK, no access error on private E
-7-
The names in a default argument expression (dcl.fct.default) are
bound at the point of declaration, and access is checked at that
point rather than at any points of use of the default argument expression.
Access checking for default arguments in function templates and in
member functions of class templates are performed as described in temp.inst.
11.1 - Access specifiers [class.access.spec]
-1- Member declarations can be labeled by an access-specifier (clause class.derived):
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:access-specifier : member-specificationopt
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 };
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 };
-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 };
-1- If a class is declared to be a base class (clause 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 public 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 private access specifier, the public and protected members of the base class are accessible as private members of the derived class*.
[Footnote: As specified previously in clause class.access, private members of a base class remain inaccessible even to derived classes unless friend declarations within the base class declaration are used to grant access explicitly. --- end foonote]
-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:
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.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 { /* ... */ };
-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; // 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. }
-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 and friends of a class X can implicitly convert an X* to a pointer to a private or protected immediate base class of X. ] The access to a member is affected by the class in which the member is named. This naming class is the class in which the member name was looked 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 (expr.ref) 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), the class naming the member is the class named by the nested-name-specifier of the qualified-id (that is, T). If the member m is accessible when named in the naming class according to the rules below, the access to m is nonetheless ill-formed if the type of p cannot be implicitly converted to type T (for example, if T is an inaccessible base class of p's class). ] A member m is accessible when named in class N if
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 cast to A*, // and f has access to i in A }
-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 effect of an access declaration qualified-id ; is defined to be equivalent to the declaration using qualified-id ;.*
[Footnote: 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 encouraged to use using-declarations, rather than the new capabilities of access declarations, in new code. --- end foonote]
-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; };
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 function bf can use the members a, b, c, z, z1, bf, x, and y. The function 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 protected or private base class of X, xf would have the same privileges as before, but ff would have no access at all. ]class X : public D { int xf(); }; int ef(D&); int ff(X&);
-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); }
-2- Declaring a class to be a friend implies that the names of private and protected members from the class granting friendship can be accessed in declarations of members of the befriended class. [Note: this means that 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. This also means that private and protected type names from the class granting friendship can be used in the base-clause of a nested class of the friend class. However, the declarations of members of classes nested within the friend class cannot access the names of private and protected members from the class granting friendship. Also, because the base-clause of the friend class is not part of its member declarations, the base-clause of the friend class cannot access the names of the private and protected members from the class granting friendship. For example,
] An elaborated-type-specifier shall be used in a friend declaration for a class.*class A { class B { }; friend class X; }; class X : A::B { //ill-formed: A::B cannot be accessed // in the base-clause for X A::B mx; // OK: A::B used to declare member of X class Y : A::B { // OK: A::B used to declare member of X A::B my; // ill-formed: A::B cannot be accessed // to declare members of nested class of X }; };
[Footnote: The class-key of the elaborated-type-specifier is required. --- end foonote]A class shall not be defined in a friend declaration. [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 };
-3- A function first declared in a friend declaration has external linkage (basic.link). Otherwise, the function retains its previous linkage (dcl.stc).
-4- 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. [Example:
class Y { friend char* X::foo(int); //... };
-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 };
-6- No storage-class-specifier shall appear in the decl-specifier-seq of a friend declaration.
-7- A name nominated by a friend declaration shall be accessible in the scope of the class containing the friend declaration. The meaning of the friend declaration is the same whether the friend declaration appears in the private, protected or public (class.mem) portion of the class member-specification.
-8- Friendship 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 } };
class D : public B { void f(A* p) { p->a++; //error: D is not a friend of A // despite being derived from a friend } };
-9- If a friend declaration appears in a local class (class.local) and the name specified is an unqualified name, a prior declaration 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 class declaration, if there is no prior declaration, the class that is specified belongs to the innermost enclosing non-class scope, but if it is subsequently referenced, its name is not found by name lookup until a matching declaration 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; //OK, but X is a local class, not ::X friend class Y; // OK friend class Z; // OK, introduces local class Z friend void a(); // error, ::a is not considered friend void b(); // OK friend void c(); // error }; X *px; // OK, but ::X is found Z *pz; // error, no Z is found }
-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 clause class.access.*
[Footnote: This additional check does not apply to other members, e.g. static data members or enumerator member constants. --- end foonote]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). [Example:
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; //ill-formed p1->i = 2; // ill-formed 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; // 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) int B::* pmi_B = &B::i; // ill-formed int 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; //ill-formed p1->i = 2; // ill-formed p2->i = 3; // ill-formed }
-1- The access rules (clause 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. [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 }
-1- If a name can be reached by several paths through a multiple inheritance graph, the access is that of the path that gives most access. [Example:
Since W::f() is available to C::f() along the public path through B, access is allowed. ]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 };
-1- The members of a nested class have no special access to members of an enclosing class, nor to classes or functions that have granted friendship to an enclosing class; the usual access rules (clause class.access) shall be obeyed. The members of an enclosing class have no special access to members of a nested class; the usual access rules (clause class.access) shall be obeyed. [Example:
class E { int x; class B { };
class I { B b; //error: E::B is private int y; void f(E* p, int i) { p->x = i; // error: E::x is private } };
int g(I* p) { return p->y; //error: I::y is private } };
-2- [Note: because a base-clause for a nested class is part of the declaration of the nested class itself (and not part of the declarations of the members of the nested class), the base-clause may refer to the private members of the enclosing class. For example,
class C { class A { }; A *p; //OK class B : A // OK { A *q; // OK because of injection of name A in A C::A *r; // error, C::A is inaccessible B *s; // OK because of injection of name B in B C::B *t; // error, C::B is inaccessible }; };