我试图完全理解C ++标准[class.access]部分的多个段落中定义的成员访问规则。它们相当complex or even confusing,因此我需要简短但准确而详尽的摘要。
我编译了[[1]]该程序在多种情况下测试受保护成员的可访问性(因为受保护成员的规则最复杂):#include <iostream>
class B {
protected:
int i = 1;
static int const I = 1;
};
class X: public B {
protected:
int j = 2;
static int const J = 2;
public:
void f();
friend void g();
};
class D: public X {
protected:
int k = 3;
static int const K = 3;
};
void X::f() {
B b;
X x;
D d;
//std::cout << b.i; // error: 'i' is a protected member of 'B'
std::cout << b.I;
std::cout << x.i;
std::cout << x.I;
std::cout << x.j;
std::cout << x.J;
std::cout << d.i;
std::cout << d.I;
std::cout << d.j;
std::cout << d.J;
//std::cout << d.k; // error: 'k' is a protected member of 'D'
//std::cout << d.K; // error: 'K' is a protected member of 'D'
}
void g() {
B b;
X x;
D d;
//std::cout << b.i; // error: 'i' is a protected member of 'B'
//std::cout << b.I; // error: 'I' is a protected member of 'B'
std::cout << x.i;
std::cout << x.I;
std::cout << x.j;
std::cout << x.J;
std::cout << d.i;
std::cout << d.I;
std::cout << d.j;
std::cout << d.J;
//std::cout << d.k; // error: 'k' is a protected member of 'D'
//std::cout << d.K; // error: 'K' is a protected member of 'D'
}
int main() {
B b;
X x;
D d;
//std::cout << b.i; // error: 'i' is a protected member of 'B'
//std::cout << b.I; // error: 'I' is a protected member of 'B'
//std::cout << x.i; // error: 'i' is a protected member of 'B'
//std::cout << x.I; // error: 'I' is a protected member of 'B'
//std::cout << x.j; // error: 'j' is a protected member of 'X'
//std::cout << x.J; // error: 'J' is a protected member of 'X'
//std::cout << d.i; // error: 'i' is a protected member of 'B'
//std::cout << d.I; // error: 'I' is a protected member of 'B'
//std::cout << d.j; // error: 'j' is a protected member of 'X'
//std::cout << d.J; // error: 'J' is a protected member of 'X'
//std::cout << d.k; // error: 'k' is a protected member of 'D'
//std::cout << d.K; // error: 'K' is a protected member of 'D'
return 0;
}
我在可访问性方面得出了这个结论:2类的direct
1
我在C ++ 17中使用了Clang 9.0.0编译器。2
对类成员的访问可以是直接的,即通过该类的访问(direct access),也可以是间接的,即通过该类的派生类的访问(继承访问
)。由于从派生类继承的成员可以从执行访问的实体的角度(在[class.access/base-1]中指定的可访问性发生变化)的角度被视为派生类的成员of,因此对类成员的继承访问可以被同化以直接访问该类的派生类的继承成员。换句话说,仅需要考虑直接访问。3我的条款在这里与标准[class.access/base-5.4]的引用条款略有不同:如果在类N中被命名,则成员R在点R是可访问的
……
…
- 存在一个在N处可访问的N的基类B,当在类B中命名时,m在R处可访问。
这是因为编译器的行为有所不同,我的感觉是编译器是正确的。我认为标准的条款有两个问题:
d.*
中引发对main
访问的错误而执行的操作;应该将N类中的成员m限制为从B类继承,而不是被N类覆盖(这是编译器将通过引发d.i
,d.I
,d.j
和[如果您在程序的d.J
中覆盖了X::f
,g
,i
和I
,则C0]将访问j
和J
。