(delphi11最新学习资料) Object Pascal 学习笔记---第8章第3节(保护字段和封装)

news/2024/5/3 13:12:14

8.3 保护字段和封装:

TNewDate 类中 GetText 方法的代码只有在与 TDate 类相同的单元中编写时才能编译。事实上,这个方法访问的是父类的 FDate 的私有字段。如果我们想将子类放在一个新的单元中,就必须将 FDate 字段声明为protected(或者strict protected),或者在父类中添加一个简单的protected方法来读取私有字段的值。

​ 一些开发人员认为,第一种解决方案是最好的,因为将大部分字段声明为protected会使类的可扩展性更强,也更容易编写子类。然而,这违反了封装的理念。在一个庞大的类层次结构中,更改基类中某些protected字段的定义就像改变某些全局数据结构一样困难。如果有十个派生类访问这些数据,那么改变其定义就意味着可能要修改这十个类中的代码。

​ 换句话说,灵活性、扩展性和封装性往往成为相互冲突的目标。当这种情况发生时,你应该尽量倾向于封装。如果能在不牺牲灵活性的前提下做到这一点,那就更好了。通常,这种中间解决方案可以通过使用虚方法来实现,我将在下文 "后期绑定和多态性 "一节中详细讨论这个话题。如果为了加快子类的编码速度而不使用封装,那么你的设计可能就没有遵循面向对象的原则。

​ 请记住,protected字段与private字段具有相同的访问规则,因此同一单元中的任何其他类都可以访问其他类的protected成员。如前一章所述,通过使用strict protected访问指定符,可以实现更强的封装。

8.3.1 使用"Protected"黑客技术

​ 如果你是 Object Pascal 和 OOP 的新手,这将是一个相当高级的章节。第一次阅读这本书时,你可能想跳过这部分内容,因为它可能会让你感到相当困惑。

​ 鉴于单元保护的工作原理,除非使用strict protected 关键字,否则即使是当前单元中声明的类的基类的受保护成员也可以被直接访问。这就是通常所说的 "protected hack "背后的原理,即定义一个与其基类完全相同的派生类的唯一目的就是访问基类的受保护成员。下面是它的工作原理。

​ 我们已经看到,一个类的私有数据和受保护数据可以被与该类出现在同一单元中的任何函数或方法访问。例如,请看这个简单的类(保护示例的一部分):

typeTTest = classprotectedFProtectedData: Integer;publicPublicData: Integer;function GetValue: string;end;

​ GetValue方法只是返回包含两个整数值的字符串:

function TTest.GetValue: string;
beginResult := Format('Public: %d, Protected: %d', [PublicData, FProtectedData]);
end;

​ 一旦将这个类放在自己的单元中,您将无法直接从其他单元访问其受保护的部分。因此,如果您编写以下代码,

procedure TForm1.Button1Click(Sender: TObject);
varObj: TTest;
beginObj := TTest.Create;Obj.PublicData := 10;Obj.FProtectedData := 20; // 编译不通过Show(Obj.GetValue);Obj.Free;
end;

​ 编译器将报出错误消息“Undeclared identifier: ‘FProtectedData’”。此时,您可能认为没有办法直接访问在不同单元中定义的类的protected数据。然而,还是有办法的。

​ 考虑一下如果创建一个明显无用的派生类会发生什么,例如:

typeTTestAccess = class(TTest);

​ 现在,在声明它的同一单元中,您可以调用 TTestAccess 类的任何protected方法。事实上,您可以调用在同一单元中声明的类的protected方法。

​ 这对使用 TTest 类对象有什么帮助呢?考虑到这两个类共享完全相同的内存布局(因为没有任何区别),您可以强制编译器将一个类的对象当作另一个类的对象来处理,这通常是一种不安全的类型转换:

procedure TForm1.Button2Click(Sender: TObject);
varObj: TTest;
beginObj := TTest.Create;Obj.PublicData := 10;TTestAccess(Obj).FProtectedData := 20; // 编译通过!Show(Obj.GetValue);Obj.Free;

​ 这段代码编译并正常工作,正如您通过运行Protection示例所看到的。同样,原因是 TTestAccess 类自动继承了 TTest 基类的受保护字段,而且由于 TTestAccess 类与试图访问继承字段中数据的代码位于同一单元,因此受保护的数据是可访问的。

​ 既然我已经向你演示了如何做到这一点,我必须警告你,以这种方式违反类保护机制很可能会导致程序出错(因为你访问了确实不应该访问的数据),而且它与良好的 OOP 方法论背道而驰。不过,在极少数情况下,使用这种技术是最好的解决方案,这一点你可以通过查看库源代码和许多组件的代码来了解。

​ 总的来说,这种技术是一种 "黑客 "行为,应尽可能避免使用,尽管它可以被视为语言规范的一部分,并适用于所有平台以及所有现在和过去的 Object Pascal 版本。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.cpky.cn/p/11259.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

MySQL生产环境常见故障及解决方案汇总

MySQL生产环境常见故障及解决方案汇总 1. MySQL主从同步异常故障1.1. 情景说明1.2. 排查过程1.3. 数据同步2. MySQL慢查询故障1. MySQL主从同步异常故障 1.1. 情景说明 MySQL主库网卡需要更换IP地址,并将原IP地址配置为MySQL集群的VIP地址,上层应用程序其实不需要更改连接My…

2024最新版克魔助手抓包教程(9) - 克魔助手 IOS 数据抓包

引言 在移动应用程序的开发中,了解应用程序的网络通信是至关重要的。数据抓包是一种很好的方法,可以让我们分析应用程序的网络请求和响应,了解应用程序的网络操作情况。克魔助手是一款非常强大的抓包工具,可以帮助我们在 Android …

全局UI方法-弹窗二-列表选择弹窗(ActionSheet)

1、描述 定义列表弹窗 2、接口 ActionSheet.show(value:{ title: string | Resource, message: string | Resource, autoCancel?: boolean, confrim?: {value: string | Resource, action: () > void }, cancel?: () > void, alignment?: DialogAlignment, …

wireshark流量分析

wireshark流量分析 着色规则: 显示自定义列 wireshark 默认显示列 No:编号,即pacp开始的帧号 Time:时间,分解为纳秒 Source:源地址,通常为IPv4、IPv6、以太网地址 Destination:目的地址,通常为IPv4、IPv6、以太网地…

增强现实(AR)在广告中的力量

The Power of AR in Advertising 写在前面 增强现实(AR -Augmented Reality)是指借助软件、应用程序和智能手机、平板电脑或耳机等设备,为日常生活添加视觉和音频元素的技术。如今,品牌和广告商可以在营销活动中使用AR&#xff0…

【MATLAB源码-第172期】基于matlab的小波变换能量率BP神经网络的机械轴承故障分析以及识别,附带程序说明。

操作环境: MATLAB 2022a 1、算法描述 在现代工业生产中,轴承是最为常见和关键的机械基础部件之一,其性能状态直接影响着整个机械系统的稳定性和可靠性。由于轴承在运行过程中不断承受高负荷和摩擦,故障发生的概率相对较高。轴承…