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

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 "背后的原理,即定义一个与其基类完全相同的派生类的唯一目的就是访问基类的受保护成员。下面是它的工作原理。

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

type
  TTest = class
  protected
    FProtectedData: Integer;
  public
    PublicData: Integer;
    function GetValue: string;
  end;

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

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

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

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

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

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

type
  TTestAccess = class(TTest);

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

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

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

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

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

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

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

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

相关文章

【redis】linux安装redis

目录 1. 下载redis2. 上传并解压3. 安装4. redis配置5. 启动redis-server服务 1. 下载redis 1.Redis官网2.历史版本 2. 上传并解压 1.上传到/opt/redis 2.解压 tar zxvf redis-5.0.2.tar.gz 3. 安装 1.安装gcc yum install gcc-c2.make命令 # cd /opt/redis sudo make3.…

Elment ui 动态表格与表单校验 列表数据 组件

组件做个记录&#xff0c;方便以后会用到。 效果&#xff1a; 代码 &#xff1a; <template><el-dialog title"商品详情" :visible.sync"dialogVisible" width"80%"><el-tabs v-model"activeTab"><el-tab-pane…

第十二章:预处理命令

文章目录 第十二章&#xff1a;预处理命令宏定义无参宏定义带参数的宏定义 文件包含处理 第十二章&#xff1a;预处理命令 作用&#xff1a;由编译预处理程序对程序中的特殊命令作出解释&#xff0c;以产生新的源程序对其进行正式编译 C语言与其他语言的重要区别就是可以使用预…

环境温度对测量平板有什么影响

环境温度可以对测量平板有影响。温度变化可以导致平板的尺寸发生变化。根据热膨胀原理&#xff0c;当环境温度升高时&#xff0c;平板的尺寸会扩大&#xff1b;当环境温度降低时&#xff0c;平板的尺寸会缩小。这种尺寸变化可能会导致测量结果的误差。因此&#xff0c;在测量平…

OSCP靶场--RubyDome

OSCP靶场–RubyDome 考点(CVE-2022-25765 suid ruby提权) 1.nmap扫描 ┌──(root㉿kali)-[~/Desktop] └─# nmap -Pn -sC -sV 192.168.249.22 --min-rate 2500 Starting Nmap 7.92 ( https://nmap.org ) at 2024-03-29 00:28 EDT Nmap scan report for 192.168.249.22 Hos…

mysql 常见运算符

学习了mysql数据类型&#xff0c;接下来学习mysql常见运算符。 2&#xff0c;常见运算符介绍 运算符连接表达式中各个操作数&#xff0c;其作用是用来指明对操作数所进行的运算。运用运算符 可以更加灵活地使用表中的数据&#xff0c;常见的运算符类型有&#xff1a;算…

阿里云魔搭发起“ModelScope-Sora开源计划”,将为中国类Sora模型开发提供一站式工具链

在2024年3月23日的全球开发者先锋大会上&#xff0c;阿里云的魔搭社区宣布了一个新计划&#xff1a;“ModelScope-Sora开源计划”。这个计划旨在通过开源方式&#xff0c;帮助中国在Sora模型类型上做出更多创新。这个计划提供了一整套工具&#xff0c;包括处理数据的工具、多模…

【御控物联】 IOT异构数据JSON转化(场景案例一)

文章目录 前言技术资料 前言 随着物联网、大数据、智能制造技术的不断发展&#xff0c;越来越多的企业正在进行工厂的智能化转型升级。转型升级第一步往往是设备的智能化改造&#xff0c;助力设备数据快速上云&#xff0c;实现设备数据共享和场景互联。然而&#xff0c;在生产…

车道线检测_Canny算子边缘检测_1

Canny算子边缘检测&#xff08;原理&#xff09; Canny算子边缘检测是一种经典的图像处理算法&#xff0c;由John F. Canny于1986年提出&#xff0c;用于精确、可靠地检测数字图像中的边缘特征。该算法设计时考虑了三个关键目标&#xff1a;低错误率&#xff08;即尽可能多地检…

衰老抑制剂原知因起源金NMN热销,“海弗里克极限”将被打破?

美国著名生物学家列奥纳多 海弗里克 , 在 1961 年研究人类胎儿的细胞群体分裂次数时提出了著名的 " 海弗里克极限 " 理论。该理论认为 , 正常细胞分裂的周期是 2-3 年 , 分裂次数大概是 50 次 , 得出人类的极限寿命高达 150 岁。半个世纪后 , 世界上最长寿的人 , 打…

ssm 科研奖励申报管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 ssm 科研奖励申报管理系统是一套完善的信息系统&#xff0c;结合springMVC框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用…

拆分巨石:将MVPS和MVAS应用于遗留应用程序——可持续架构(六)

前言 MVP 和 MVA 的概念不仅适用于新应用程序&#xff1b;它们提供了一种新颖的方式来审视对遗留系统的范围变更&#xff0c;以防止过快地承担过多的变化 - 参见图1。MVA 可以帮助组织评估和更新其技术标准&#xff0c;通过展示新技术如何真正对支持 MVP 至关重要。创建 MVA 可…

Flutter 使用 AndroidStudio 给(Android 安卓)进行签名方法

一、使用 AndroidStudio 创建签名 使用 AndroidStudio 打开 Flutter项目中的 android 文件夹首次打开 AndroidStudio 会加载一会。菜单栏 &#xff1a; Build -> Generate Signed Bundle APK... 选中 APK -> Next点击Create new....下面按照需求填写即可- 文件夹选择 项…

绿联 安装Uptime Kuma - 一款开源的服务器监控和状态检测工具

Uptime Kuma 功能简介 Uptime Kuma 是一款开源的服务器监控和状态检测工具&#xff0c;它帮助您跟踪服务器的可用性、性能和健康状态。 主要功能&#xff1a; 服务器监控 Uptime Kuma 可以监控多个服务器&#xff0c;包括 Web 服务器、数据库服务器、应用程序服务器等。 它会定…

element-ui-plus el-tree 树形结构如何自定义内容

element-ui-plus el-tree 树形结构如何自定义内容 本文提及的 elementUI 版本 为 elementUI Plus 版本 一、需求 项目中遇到一个需要设置权限的地方&#xff0c;但目录和权限是放在一起的&#xff0c;这样就很不好区分类别&#xff0c;为了区分类别&#xff0c;就需要自定义树…

前端bugs

问题&#xff1a; Failed to load plugin typescript-eslint declared in package.json eslint-config-react-app#overrides[0]: Cannot find module eslint/package.json 解决&#xff1a; google了一晚上还得是chatgpt管用 运行以下命令【同时还要注意项目本身使用的Node版…

【spring】@Primary注解学习

Primary介绍 Primary 是 Spring 框架中的一个注解&#xff0c;用于在多个相同类型的 bean 中指定一个默认的 bean。当 Spring 容器在自动装配时遇到类型冲突&#xff0c;即存在多个相同类型的 bean 时&#xff0c;如果没有使用 Qualifier 或其他方式指定具体的 bean&#xff0…

AI计算平台设计方案:901-基于3U VPX的图像数据AI计算平台

一、产品概述 设备基于3U VPX的导冷结构&#xff0c;集成FPGA接口预处理卡&#xff0c;GPU板卡、飞腾ARM处理卡&#xff0c;实现光纤、差分电口或者Camera link的图像接入&#xff0c;FPGA信号预处理&#xff0c;GPU AI计算&#xff0c;飞腾ARM的采集管理存储。 二、系统…

Linux基础命令篇:操作系统服务管理(systemctl service)

Linux基础命令篇&#xff1a;操作系统服务管理&#xff08;systemctl & service&#xff09; service和systemctl是两个用于管理Linux系统服务的命令。它们分别属于SysV init和systemd系统&#xff0c;这两个系统是Linux中用于初始化和管理服务的不同框架。在许多现代Linux…

visual studio报:引发的异常:“System.DllNotFoundException”(位于 ConsoleCAN1.exe 中)

最近在重构CAN通信的代码&#xff0c;把论文中的java转为C#实现&#xff0c;由于某种原因&#xff0c;java不能复现&#xff0c;所以转为c#。 然而c#的重构过程遇到许多问题&#xff0c;因为两种语言的编程方式、线程等等实现上有所差异。 其中一个错误&#xff1a; 引发的异…