访问说明符
在 成员说明 中的 类/结构 或 联合 中,定义后续成员的访问权限。
在 基类说明符 中的 派生类 声明中,定义后续基类的继承成员的访问权限。
内容 |
[编辑] 语法
public : 成员声明 |
(1) | ||||||||
protected : 成员声明 |
(2) | ||||||||
private : 成员声明 |
(3) | ||||||||
public 基类 | (4) | ||||||||
protected 基类 | (5) | ||||||||
private 基类 | (6) | ||||||||
无论公有、保护还是私有继承,基类的私有成员始终无法被派生类访问。
[编辑] 解释
每个 类 成员(静态、非静态、函数、类型等)的名称都与一个关联的“成员访问”相关联。当成员的名称在程序中的任何地方使用时,都会检查其访问权限,如果它不满足访问规则,程序将无法编译。
#include <iostream> class Example { public: // all declarations after this point are public void add(int x) // member "add" has public access { n += x; // OK: private Example::n can be accessed from Example::add } private: // all declarations after this point are private int n = 0; // member "n" has private access }; int main() { Example e; e.add(1); // OK: public Example::add can be accessed from main // e.n = 7; // error: private Example::n cannot be accessed from main }
访问说明符使类作者能够决定哪些类成员对类用户(即接口)是可访问的,哪些成员是供类内部使用(即实现)。
[编辑] 详细说明
一个类的所有成员(成员函数的函数体,成员对象的初始化器以及整个嵌套类定义)都可以访问该类可以访问的所有名称。成员函数中的局部类可以访问成员函数可以访问的所有名称。
用关键字class
定义的类默认情况下对它的成员和基类具有私有访问权限。用关键字struct
定义的类默认情况下对它的成员和基类具有公有访问权限。联合体默认情况下对它的成员具有公有访问权限。
要授予其他函数或类对受保护或私有成员的访问权限,可以使用友元声明。
可访问性适用于所有名称,而不管它们的来源如何,因此会检查typedef或using 声明(除了继承构造函数)引入的名称,而不是它引用的名称。
class A : X { class B {}; // B is private in A public: typedef B BB; // BB is public }; void f() { A::B y; // error: A::B is private A::BB x; // OK: A::BB is public }
成员访问不会影响可见性:私有成员和私有继承成员的名称是可见的,并且会被重载解析考虑,对不可访问的基类的隐式转换仍然会被考虑,等等。成员访问检查是在解释任何给定的语言结构之后的最后一步。这条规则的目的是,将任何private
替换为public
永远不会改变程序的行为。
对默认函数参数以及默认模板参数中使用的名称进行的访问检查是在声明时进行的,而不是在使用时进行的。
对虚函数名称的访问规则是在调用点使用用于表示调用成员函数的对象的表达式的类型进行检查。最终覆盖者的访问权限将被忽略。
struct B { virtual int f(); // f is public in B }; class D : public B { private: int f(); // f is private in D }; void f() { D d; B& b = d; b.f(); // OK: B::f is public, D::f is invoked even though it's private d.f(); // error: D::f is private }
根据非限定名称查找是私有的名称,可以通过限定名称查找访问。
class A {}; class B : private A {}; class C : public B { A* p; // error: unqualified name lookup finds A as the private base of B ::A* q; // OK: qualified name lookup finds the namespace-level declaration };
在继承图中可以通过多个路径访问的名称具有访问权限最高的路径的访问权限。
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: W is accessible to C through B } };
可以在类中以任何顺序出现任意数量的访问说明符。成员访问说明符可能会影响类布局:非静态数据成员的地址仅保证按照声明顺序递增,前提是这些成员未被访问说明符隔开(直到 C++11)具有相同的访问权限(自 C++11 起)。
对于标准布局类型,所有非静态数据成员必须具有相同的访问权限。 |
(自 C++11 起) |
当成员在同一个类中被重新声明时,它必须在相同的成员访问权限下进行重新声明。
struct S { class A; // S::A is public private: class A {}; // error: cannot change access };
[edit] 公有成员访问
公有成员构成类公有接口的一部分(公有接口的其他部分是通过ADL找到的非成员函数)。
类的公有成员可以在任何地方访问。
class S { public: // n, E, A, B, C, U, f are public members int n; enum E {A, B, C}; struct U {}; static void f() {} }; int main() { S::f(); // S::f is accessible in main S s; s.n = S::B; // S::n and S::B are accessible in main S::U x; // S::U is accessible in main }
[edit] 受保护成员访问
受保护成员构成类对其派生类的接口(这与类的公有接口不同)。
类的受保护成员只能被以下访问:
struct Base { protected: int i; private: void g(Base& b, struct Derived& d); }; struct Derived : Base { friend void h(Base& b, Derived& d); void f(Base& b, Derived& d) // member function of a derived class { ++d.i; // OK: the type of d is Derived ++i; // OK: the type of the implied '*this' is Derived // ++b.i; // error: can't access a protected member through // Base (otherwise it would be possible to change // other derived classes, like a hypothetical // Derived2, base implementation) } }; void Base::g(Base& b, Derived& d) // member function of Base { ++i; // OK ++b.i; // OK ++d.i; // OK } void h(Base& b, Derived& d) // Friend of Derived { ++d.i; // OK: friend of Derived can access a protected // member through an object of Derived // ++b.i; // error: friend of Derived is not a friend of Base } void x(Base& b, Derived& d) // non-member non-friend { // ++b.i; // error: no access from non-member // ++d.i; // error: no access from non-member }
当形成指向受保护成员的指针时,它必须在声明中使用派生类。
struct Base { protected: int i; }; struct Derived : Base { void f() { // int Base::* ptr = &Base::i; // error: must name using Derived int Base::* ptr = &Derived::i; // OK } };
[edit] 私有成员访问
私有成员构成类的实现,以及类其他成员的私有接口。
类的私有成员只能被该类的成员和友元访问,而不管这些成员是否在相同或不同的实例上。
class S { private: int n; // S::n is private public: S() : n(10) {} // this->n is accessible in S::S S(const S& other) : n(other.n) {} // other.n is accessible in S::S };
显式转换(C 风格和函数风格)允许从派生左值转换到对其私有基类的引用,或者从指向派生的指针转换到指向其私有基类的指针。
[edit] 继承
有关公有继承、受保护继承和私有继承的含义,请参见派生类。
[edit] 关键字
[edit] 缺陷报告
以下更改行为的缺陷报告已追溯应用于先前发布的 C++ 标准。
DR | 应用于 | 已发布的行为 | 正确行为 |
---|---|---|---|
CWG 1873 | C++98 | 受保护成员可被派生类的友元访问。 | 不可访问。 |