一文理解类的访问权限
前言
在类的继承体系中,关于访问权限我个人感觉一直是非常复杂,各类博客、书籍对它的解释都不够好。在这篇文章我想通过我的理解,着重解释类的继承体系中复杂的访问权限的原理。注意:我将在个人理解中加入 inaccessible 的访问权限,帮助理解烦杂的访问权限体系。
继承后访问权限
四级访问权限
类的访问权限分为三级:private / protected / public。但我认为增加一级 inaccessible 更容易理解。
首先,我们来回顾一下以上三个访问权限连同 inaccessible 分别是什么访问限制:
public:公有的,类外、类内、派生类均可访问public下的类成员。protected:受保护的,类外不可访问protected下的类成员,类内、派生类成员可访问。private:私有的,类外、派生类不可访问private下的类成员,类内成员可访问。inaccessible:不可访问的,类外、类内、派生类均不可访问inaccessible的类成员。
换言之,public 对于类外是可访问的,public / protected 对于派生类是可访问的,public / protected / private 对于类内是可访问的,而 inaccessible 对谁都是不可访问的。
为什么提出 protected 权限
从上面可以看出,protected 只对派生类有所区别,它正是用于为派生类和类外提供区别的权限而提出的。受保护成员可以被派生类访问,而无法被类外访问。
为什么我引入了 inaccessible 权限
为了直观表示在继承后,成员访问权限的变化,我们可以使用状态转移表或状态图的方式表示。但这样有一个问题,private 成员继承后转移为何状态?因此这里设立了 inaccessible 状态,这样我们可以画例如这样的状态图,这为我们后面的诸多解释提供方便:

再次强调,inaccessible 是我个人定义的概念,用于方便理解类的访问权限。inaccessible 成员实际就是类内不存在的成员,它的所有表现都与不存在该成员相同。(private 在类外有时也会出现与不存在该成员不同的表现。)
访问权限的继承
类的访问权限在继承过程中的变化如下:
| 继承方式 / 继承后权限 / 继承前权限 | public |
protected |
private |
inaccessible |
|---|---|---|---|---|
public(公有继承) |
public |
protected |
inaccessible |
inaccessible |
protected(受保护继承) |
protected |
prtected |
inaccessible |
inaccessible |
private(私有继承) |
private |
private |
inaccessible |
inaccessible |
从表中可以看的很清楚,继承后权限就是 private 变 inaccessible,其余不变,然后所有全部和继承方式取最小权限的结果。
派生类到基类转换的可访问性
其实所有间接继承无法完成或者间接类型转换无法完成,都是基于上面的继承体系产生的结果(构造函数的 using 始终是个特例,这里将它排除在外)。这里我们主要对下面三类派生类到基类转换作解释:
类外转换
protected 或 private 继承方式下,类外 无法实现 派生类到基类的转换。反之,是合法的。
因为 protected 或 private 继承方式将 public 成员转换为 protected 或 private 成员,对于类外,这是从可访问到不可访问的转换,类外想篡取不该有的访问权限,当然是不允许的!
flowchart TD
subgraph 1[基类]
subgraph 10[类外可访问]
11(public)
end
12(protected)
13(private)
14(inaccessible)
end
subgraph 2[派生类]
21(public)
subgraph 2a[类外不可访问]
22(protected)
23(private)
24(inaccessible)
end
end
1 ==>|protected 继承| 2
2 -->|派生类到基类的转换| 1
11 & 12 .-> 22
13 & 14 .-> 24
22 -->|试图篡取权限| 11
subgraph 3[基类]
subgraph 30[类外可访问]
31(public)
end
32(protected)
33(private)
34(inaccessible)
end
subgraph 4[派生类]
41(public)
subgraph 4a[类外不可访问]
42(protected)
43(private)
44(inaccessible)
end
end
3 ==>|public 继承| 4
4 -->|派生类到基类的转换| 3
31 .-> 41
32 .-> 42
33 & 34 .-> 44
以 protected 继承为例,可以看到存在从类外不可访问到类外可访问的篡权;再来看 public 继承则不存在篡权。
直接基类转换
不论以何继承方式,类内派生类到 直接基类 的转换都是 合法的 。
因为对于派生类,基类成员原本可见的成员对于派生类依然是可见的,不存在篡取访问权限;有人质疑 private 成员在派生类中变为 inaccessible,但 private 在基类中对于派生类也是不可见的,并没有得到新的权限。
flowchart TD
subgraph 1[基类]
subgraph 10[派生类可访问]
11(public)
12(protected)
end
13(private)
14(inaccessible)
end
subgraph 2[派生类]
21(public)
22(protected)
23(private)
subgraph 2a[类内不可访问]
24(inaccessible)
end
end
1 ==>|private 继承| 2
2 -->|派生类到基类的转换| 1
11 & 12 .-> 23
13 & 14 .-> 24
以 private 继承为例,派生类对基类来说是 “派生类”,派生类对派生类来说是 “类内”,这里不存在篡权。
间接基类转换
派生类的 private 继承方式下,再派生类(派生类的派生类)不论以何继承方式,其内都 无法实现 派生类到基类的转换。反之,是合法的。
这次我们直接看图:
flowchart TD
subgraph 1[基类]
subgraph 10[类外可访问]
11(public)
end
12(protected)
13(private)
14(inaccessible)
end
subgraph 2[派生类]
21(public)
22(protected)
subgraph 2a[派生类不可访问]
23(private)
24(inaccessible)
end
end
1 ==>|private 继承| 2
2 -->|派生类到基类的转换| 1
11 & 12 .-> 23
13 & 14 .-> 24
23 -->|试图篡取权限| 11
subgraph 3[基类]
subgraph 30[类外可访问]
31(public)
end
32(protected)
33(private)
34(inaccessible)
end
subgraph 4[派生类]
41(public)
42(protected)
subgraph 4a[派生类不可访问]
43(private)
44(inaccessible)
end
end
3 ==>|protected 继承| 4
4 -->|派生类到基类的转换| 3
31 & 32 .-> 42
33 & 34 .-> 44
派生类对基类来说是 “派生类”,派生类对派生类来说是 “类内”。在以 private 继承的示例中,可以看到存在从类外不可访问到类外可访问的篡权;在以 protected 继承的示例中,则不存在篡权的情况。
事实上,不论是我定义的四级访问权限,还是原先的三级访问权限,其实质都只是用于描述可访问性的中间过程,以及为不同对象提供区别的可访问性。而最终一个访问是否合法,始终直接取决于可访问性,而非访问权限。
