为什么嵌套类可以让包含类访问子类的受保护数据?

Zac*_* F. 2 delphi scope class

这个问题可能有点令人困惑,最好通过一个例子来说明:

unit Test
interface
type
  TestClass = class()
    Splitter1: TcxSplitter;
    procedure SomeMethod();
  end;

implementation
uses
  cxSplitter;

// Locally-declared child type
type
  TcxSplitterAccess = class(TcxSplitter);

procedure TestClass.SomeMethod()
var
  pos: integer;
begin
  // Access to protected field FPositionBeforeClose by casting
  pos := TcxSplitterAccess(Splitter1).FPositionBeforeClose;
end;

Run Code Online (Sandbox Code Playgroud)

请注意,在实现部分中,有一个类型TcxSplitterAccess被声明为TcxSplitter该类的子类。在该方法中SomeMethod(),属于类TestClass,一个TcxSplitter对象被强制转换为本地声明的TcxSplitterAccess类,然后受保护的字段是对象访问。

作为具有 Java、C++、C# 等语言背景的人,这让我感到惊讶。在这些语言中,只要您是从该对象的类型或继承类型。例如,类中的方法ClazzA可以访问其他ClazzA对象的私有字段,因为访问是在类型级别而不是实例级别强制执行的。用这些语言在本地声明一个类不会让包含类访问本地类的受保护数据(编辑:正如评论中指出的那样,至少对于 Java 来说实际上不是这样)。

但是,在此示例中,该类型通过首先转换为该类型TestClass来直接访问TcxSplitter对象上的受保护字段TcxSplitterAccess。我无法找到有关此“技巧”为何有效的文档。Delphi 处理访问级别是否与类 Java 语言根本不同,并允许这种事情?无论如何,为什么这个技巧有效?

虽然我通过使用嵌套的继承类来访问父类上的字段(这破坏了封装,我不应该这样做)偶然发现了这种行为,但在这里使用继承是不必要的。如果嵌套类没有从类继承,而是定义了自己的受保护字段,则TestClass仍然可以访问这些受保护字段。

Rem*_*eau 5

Aunit本身具有隐含的友谊语义。在同一个unit声明的类型是彼此的“朋友”(类似于friend在 C++ 中),因此可以访问彼此的privateprotected成员(但不能访问strict privatestrict protected成员)。

所以,在这种情况下:

  • TcxSplitterAccess派生自TcxSplitter,因此通过普通类继承TcxSplitterAccess继承所有protected(但不是private)成员TcxSplitter
  • TestClass在相同的被声明unitTcxSplitterAccess,使TestClass具有访问所有的protected成员TcxSplitterAccess包括所述protected的部件TcxSplitter(以及protected它的祖先的成员)。
  • FPositionBeforeCloseprotectedTcxSplitter

所以,这就是为什么TestClass.SomeMethod()能够访问FPositionBeforeClose时型坯连铸Splitter1对象TcxSplitterAccess

Delphi 文档涵盖了这一点:

私有、受保护、公共和已发布声明

类和对象 (Delphi):类成员的可见性