一文理解类的访问权限
前言
在类的继承体系中,关于访问权限我个人感觉一直是非常复杂,各类博客、书籍对它的解释都不够好。在这篇文章我想通过我的理解,着重解释类的继承体系中复杂的访问权限的原理。注意:我将在个人理解中加入 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
继承的示例中,则不存在篡权的情况。
事实上,不论是我定义的四级访问权限,还是原先的三级访问权限,其实质都只是用于描述可访问性的中间过程,以及为不同对象提供区别的可访问性。而最终一个访问是否合法,始终直接取决于可访问性,而非访问权限。