为什么嵌套 class 可以让包含的 class 访问子 class 的受保护数据?
Why does nesting a class give the containing class access to the child class' protected data?
这个问题可能有点令人困惑,最好用一个例子来说明:
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;
注意在实现部分有一个类型 TcxSplitterAccess
被声明为 TcxSplitter
class 的子类型。在属于classTestClass
的方法SomeMethod()
中,将一个TcxSplitter
对象强制转换为本地声明的TcxSplitterAccess
class,然后在该对象上访问受保护的字段。
对于具有 Java、C++、C# 等语言背景的人来说,这让我感到惊讶。在这些语言中,只要您是,就可以访问对象中受保护的数据从 在该对象的类型或继承类型 中进行。例如,class ClazzA
中的方法可以访问其他 ClazzA
对象的私有字段,因为访问是在 type 级别强制执行的,而不是比 实例 水平。在这些语言中在本地声明 class 不会给予包含 class 访问本地 class' 受保护数据的权限(edit: 正如在评论,这实际上不是真的,至少 Java).
然而,在此示例中,类型 TestClass
通过首先转换为 TcxSplitterAccess
类型直接访问 TcxSplitter
对象上的受保护字段。我无法找到有关此“技巧”为何起作用的文档。 Delphi 处理访问级别的方式是否与类似 Java 的语言有根本不同并允许这种事情?无论如何,为什么这个技巧会奏效?
虽然我通过使用嵌套的、继承的 class 来访问父 class 上的字段(这破坏了封装,我不应该这样做)而偶然发现了这种行为,但使用这里的继承是不必要的。如果嵌套 class 没有继承自 class,而是定义了自己的受保护字段,TestClass
仍然可以访问这些受保护字段。
A unit
本身具有 implicit-friendship 语义。在同一个 unit
中声明的类型 是彼此的“朋友”(类似于 C++ 中的 friend
),因此可以访问彼此的 private
和 protected
名成员(但不是 strict private
或 strict protected
名成员)。
因此,在这种情况下:
TcxSplitterAccess
派生自 TcxSplitter
,因此 TcxSplitterAccess
继承 TcxSplitter
的所有 protected
(但不是 private
)成员,通过正常 class 继承。
TestClass
在与 TcxSplitterAccess
相同的 unit
中声明,因此 TestClass
可以访问 [=17= 的所有 protected
成员], 包括 TcxSplitter
的 protected
成员(及其祖先的 protected
成员)。
FPositionBeforeClose
是 protected
在 TcxSplitter
.
所以,这就是为什么 TestClass.SomeMethod()
能够在 type-casting 将 Splitter1
对象指向 TcxSplitterAccess
时访问 FPositionBeforeClose
。
Delphi 文档对此进行了介绍:
这个问题可能有点令人困惑,最好用一个例子来说明:
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;
注意在实现部分有一个类型 TcxSplitterAccess
被声明为 TcxSplitter
class 的子类型。在属于classTestClass
的方法SomeMethod()
中,将一个TcxSplitter
对象强制转换为本地声明的TcxSplitterAccess
class,然后在该对象上访问受保护的字段。
对于具有 Java、C++、C# 等语言背景的人来说,这让我感到惊讶。在这些语言中,只要您是,就可以访问对象中受保护的数据从 在该对象的类型或继承类型 中进行。例如,class ClazzA
中的方法可以访问其他 ClazzA
对象的私有字段,因为访问是在 type 级别强制执行的,而不是比 实例 水平。在这些语言中在本地声明 class 不会给予包含 class 访问本地 class' 受保护数据的权限(edit: 正如在评论,这实际上不是真的,至少 Java).
然而,在此示例中,类型 TestClass
通过首先转换为 TcxSplitterAccess
类型直接访问 TcxSplitter
对象上的受保护字段。我无法找到有关此“技巧”为何起作用的文档。 Delphi 处理访问级别的方式是否与类似 Java 的语言有根本不同并允许这种事情?无论如何,为什么这个技巧会奏效?
虽然我通过使用嵌套的、继承的 class 来访问父 class 上的字段(这破坏了封装,我不应该这样做)而偶然发现了这种行为,但使用这里的继承是不必要的。如果嵌套 class 没有继承自 class,而是定义了自己的受保护字段,TestClass
仍然可以访问这些受保护字段。
A unit
本身具有 implicit-friendship 语义。在同一个 unit
中声明的类型 是彼此的“朋友”(类似于 C++ 中的 friend
),因此可以访问彼此的 private
和 protected
名成员(但不是 strict private
或 strict protected
名成员)。
因此,在这种情况下:
TcxSplitterAccess
派生自TcxSplitter
,因此TcxSplitterAccess
继承TcxSplitter
的所有protected
(但不是private
)成员,通过正常 class 继承。TestClass
在与TcxSplitterAccess
相同的unit
中声明,因此TestClass
可以访问 [=17= 的所有protected
成员], 包括TcxSplitter
的protected
成员(及其祖先的protected
成员)。FPositionBeforeClose
是protected
在TcxSplitter
.
所以,这就是为什么 TestClass.SomeMethod()
能够在 type-casting 将 Splitter1
对象指向 TcxSplitterAccess
时访问 FPositionBeforeClose
。
Delphi 文档对此进行了介绍: