前言

在类的继承体系中,关于访问权限我个人感觉一直是非常复杂,各类博客、书籍对它的解释都不够好。在这篇文章我想通过我的理解,着重解释类的继承体系中复杂的访问权限的原理。注意:我将在个人理解中加入 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 状态,这样我们可以画例如这样的状态图,这为我们后面的诸多解释提供方便:

mermaid-diagram-2024-02-14-214610.png

再次强调,inaccessible 是我个人定义的概念,用于方便理解类的访问权限。inaccessible 成员实际就是类内不存在的成员,它的所有表现都与不存在该成员相同。(private 在类外有时也会出现与不存在该成员不同的表现。)

访问权限的继承

类的访问权限在继承过程中的变化如下:

继承方式 / 继承后权限 / 继承前权限 public protected private inaccessible
public(公有继承) public protected inaccessible inaccessible
protected(受保护继承) protected prtected inaccessible inaccessible
private(私有继承) private private inaccessible inaccessible

从表中可以看的很清楚,继承后权限就是 privateinaccessible,其余不变,然后所有全部和继承方式取最小权限的结果。


派生类到基类转换的可访问性

其实所有间接继承无法完成或者间接类型转换无法完成,都是基于上面的继承体系产生的结果(构造函数的 using 始终是个特例,这里将它排除在外)。这里我们主要对下面三类派生类到基类转换作解释:

类外转换

protectedprivate 继承方式下,类外 ​无法实现 派生类到基类的转换。反之,是合法的。

因为 protectedprivate 继承方式将 public 成员转换为 protectedprivate 成员,对于类外,这是从可访问到不可访问的转换,类外想篡取不该有的访问权限,当然是不允许的!

protected 继承为例,可以看到存在从类外不可访问到类外可访问的篡权;再来看 public 继承则不存在篡权。

直接基类转换

不论以何继承方式,类内派生类到 ​直接基类 的转换都是 ​合法的

因为对于派生类,基类成员原本可见的成员对于派生类依然是可见的,不存在篡取访问权限;有人质疑 private 成员在派生类中变为 inaccessible,但 private 在基类中对于派生类也是不可见的,并没有得到新的权限。

private 继承为例,派生类对基类来说是 “派生类”,派生类对派生类来说是 “类内”,这里不存在篡权。

间接基类转换

派生类的 private 继承方式下,再派生类(派生类的派生类)不论以何继承方式,其内都 ​无法实现 派生类到基类的转换。反之,是合法的。

这次我们直接看图:

派生类对基类来说是 “派生类”,派生类对派生类来说是 “类内”。在以 private 继承的示例中,可以看到存在从类外不可访问到类外可访问的篡权;在以 protected 继承的示例中,则不存在篡权的情况。

事实上,不论是我定义的四级访问权限,还是原先的三级访问权限,其实质都只是用于描述可访问性的中间过程,以及为不同对象提供区别的可访问性。而最终一个访问是否合法,始终直接取决于可访问性,而非访问权限。