______________________________________________________________________
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
and friends of the class in which it is declared.
--protected; that is, its name can be used only by member functions
and friends of the class in which it is declared and by member
functions and friends of classes derived from this class (see
_class.protected_).
--public; that is, its name can be used by any function.
2 Members of a class declared with the keyword class are private by
default. Members of a class declared with the keywords struct or
union are public by default. For example,
class X {
int a; // X::a is private by default
};
struct S {
int a; // S::a is public by default
};
11.1 Access specifiers [class.access.spec]
1 Member declarations may 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. For 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
};
Any number of access specifiers is allowed and no particular order is
required. For 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
};
2 The order of allocation of data members with separate access-specifier
labels is implementation dependent (_class.mem_).
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 (but see _over.dcl_). 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 class1).
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. For 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.
3 Because of the rules on pointer conversion (_conv.ptr_), a static mem
ber of a private base class may be inaccessible as an inherited name,
but accessible directly. For example,
_________________________
1) 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 declaration are used to grant ac
cess explicitly.
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 the same as 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 and bp2->mi is the same as this->mi
}
4 A base class is said to be accessible if its public members are acces
sible. 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_). It follows that members and friends of a
class X can implicitly convert an X* to a pointer to a private or pro
tected immediate base class of X.
11.3 Access declarations [class.access.dcl]
1 The access of public or protected member of a private or protected
base class can be restored to the same level in the derived class by
mentioning its qualified-id in the public (for public members of the
base class) or protected (for protected members of the base class)
part of a derived class declaration. Such mention is called an access
declaration.
2 For 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;
};
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.
3 An access declaration may not be used to restrict access to a member
that is accessible in the base class, nor may it be used to enable
access to a member that is not accessible in the base class. For
example,
class A {
public:
int z;
};
class B : private A {
public:
int a;
int x;
private:
int b;
protected:
int c;
};
class D : private B {
public:
B::a; // make `a' a public member of D
B::b; // error: attempt to grant access
// can't make `b' a public member of D
A::z; // error: attempt to grant access
protected:
B::c; // make `c' a protected member of D
B::x; // error: attempt to reduce access
// can't make `x' a protected member of D
};
class E : protected B {
public:
B::a; // make `a' a public member of E
};
The names c and x are protected members of E by virtue of its pro
tected derivation from B. An access declaration for the name of an
overloaded function adjusts the access to all functions of that name
in the base class. For example,
class X {
public:
f();
f(int);
};
class Y : private X {
public:
X::f; // makes X::f() and X::f(int) public in Y
};
4 The access to a base class member cannot be adjusted in a derived
class that also defines a member of that name. For example,
class X {
public:
void f();
};
class Y : private X {
public:
void f(int);
X::f; // error: two declarations of f
};
11.4 Friends [class.friend]
1 A friend of a class is a function 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. The following example illus
trates 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 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. For
example,
class Y {
friend char* X::foo(int);
// ...
};
All the functions of a class X can be made friends of a class Y by a
single declaration using an elaborated-type-specifier2)
(_class.name_):
class Y {
friend class X;
// ...
};
Declaring a class to be a friend also implies that private and pro
tected names from the class granting friendship can be used in the
class receiving it. For 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 For a class or function mentioned as a friend and not previously
declared, see _namespace.def_.
4 A function first declared in a friend declaration has external linkage
(_basic.link_). Otherwise, it retains its previous linkage
(_dcl.stc_).
_________________________
2) Note that the class-key of the elaborated-type-specifier is re
quired.
+------- BEGIN BOX 1 -------+
Is the following friend declaration well-formed: "friend static void
f();" ?
+------- END BOX 1 -------+
5 A function of namespace scope may be defined in a friend declaration
of a non-local class (_class.local_). The function is then inline. A
friend function 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.
6 Friend declarations are not affected by access-specifiers
(_class.mem_).
7 Friendship is neither inherited nor transitive. For 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
}
};
11.5 Protected member access [class.protected]
1 A friend or a member function of a derived class can access a pro
tected static member of a base class. A friend or a member function
of a derived class can access a protected nonstatic member of one of
its base classes only through a pointer to, reference to, or object of
the derived class itself (or any class derived from that class). When
a protected member of a base class appears in a qualified-id in a
friend or a member function of a derived class, the nested-name-
specifier must name the derived class. For example,
class B {
protected:
int i;
};
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; // illegal
p1->i = 2; // illegal
p2->i = 3; // ok (access through a D2)
int B::* pmi_B = &B::i; // illegal
int D2::* pmi_D2 = &D2::i; // ok
}
void D2::mem(B* pb, D1* p1)
{
pb->i = 1; // illegal
p1->i = 2; // illegal
i = 3; // ok (access through `this')
}
void g(B* pb, D1* p1, D2* p2)
{
pb->i = 1; // illegal
p1->i = 2; // illegal
p2->i = 3; // illegal
}
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. For example,
class B {
public:
virtual f();
};
class D : public B {
private:
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
}
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 function 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.
For 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.