(delphi11最新学习资料) Object Pascal 学习笔记---第8章第6节(安全类型转换运算符)

本文主要是介绍(delphi11最新学习资料) Object Pascal 学习笔记---第8章第6节(安全类型转换运算符),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

8.6 安全类型转换运算符

​ 正如我们之前所见,子类的语言类型兼容性规则允许你在期望祖先类的地方使用子类。如我所提到的,反向则不可能。

​ 现在假设TDog类有一个Eat方法,而TAnimal类中不存在此方法。如果变量FMyAnimal引用了一个狗,你可能希望能够调用这个函数。但如果你尝试调用,而变量指向的是另一个类,结果就会出错。通过显式类型转换,我们可能会导致令人讨厌的运行时错误(或者更糟糕的是,出现微妙的内存覆盖问题),因为编译器无法确定对象的类型是否正确,以及我们调用的方法是否确实存在。

​ 为了解决这个问题,我们可以使用基于运行时类型信息的技术。从本质上讲,因为每个对象在运行时“知道”自己的类型和父类。我们可以使用is运算符或使用TObject类的一些方法询问此信息。is运算符的参数是一个对象和一个类类型,返回值是一个布尔值:

if FMyAnimal is TDog then...

​ 只有当 FMyAnimal 对象当前引用的是 TDog 类对象或 TDog 的子类且与 TDog 兼容时,is 表达式才会返回 True。这意味着,如果测试存储在 TAnimal 变量中的 TDog 对象是否真的是 TDog 对象,测试将会成功。换句话说,如果可以安全地将对象 (FMyAnimal) 赋值给数据类型 (TDog) 的变量,则该表达式的值为 True。

注解: 实际上,is 运算符的实现是由 TObject 类的 InheritsFrom 方法提供的。因此,您可以将相同的表达式写为 FMyAnimal.InheritsFrom(TDog)。直接使用这个方法的原因是它还可以应用于类引用和不支持 is 运算符的其他特殊类型。

现在您确信动物是一只狗后,可以通过以下代码使用直接类型转换(通常是不安全的):
if FMyAnimal is TDog then
beginMyDog := TDog(FMyAnimal);Text := MyDog.Eat;
end;

​ 同样的操作也可以直接通过另一个相关的类型转换运算符 as 来完成。as 仅在请求的类与实际类兼容时才转换对象,否则将导致运行时异常。as 运算符的参数是一个对象和一个类类型,结果是一个“转换”为新的类类型的对象。我们可以编写以下片段:

MyDog := FMyAnimal as TDog;
Text := MyDog.Eat;

如果只想调用 Eat 函数,还可以使用更简洁的表示法:

(FMyAnimal as TDog).Eat;

​ 这个表达式的结果是一个 TDog 类数据类型的对象,因此您可以对其应用该类的任何方法。传统转换和使用 as 转换的区别在于,后者会检查对象的实际类型,并在类型与试图转换的类型不兼容时引发异常。引发的异常是 EInvalidCast(下一章将介绍异常)

警告:相比之下,在 C# 语言中,如果对象与类型不兼容,则 as 表达式将返回 nil,而直接类型转换将引发异常。因此,基本上这两个操作与 Object Pascal 相比是相反的。

​ 要避免这种异常,请使用 is 运算符,如果成功,则进行普通类型转换(实际上,没有理由连续使用 isas,进行两次类型检查,尽管通常会看到它们的组合使用):

if FMyAnimal is TDog thenTDog(MyAnimal).Eat;

​ 在 Object Pascal 中,这两个类型转换运算符非常有用,因为您通常希望编写可用于相同类型或不同类型的多个组件的通用代码。例如,当将组件作为参数传递给事件响应方法时,使用通用数据类型(TObject)时,通常需要将其转换回原始组件类型:

procedure TForm1.Button1Click(Sender: TObject);
beginif Sender is TButton then...
end;

这是一种常用技术,我将在后面的示例中使用它(事件将在第 10 章中介绍)。

​ 这两个类型转换运算符 isas 非常强大,您可能会被诱使将其视为标准的编程构造。尽管它们确实很强大,但您可能应该将它们的使用限制在特殊情况下。当您需要解决涉及多个类的复杂问题时,请首先尝试使用多态。只有在特殊情况下,多态无法应用时,才应尝试使用类型转换运算符来作为补充。

注意:使用类型转换操作符会对性能产生轻微的负面影响,因为它必须遍历类的层次结构,以查看类型转换是否正确。正如我们所看到的,虚拟方法调用只需要查找内存,速度要快得多。

这篇关于(delphi11最新学习资料) Object Pascal 学习笔记---第8章第6节(安全类型转换运算符)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/879355

相关文章

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

Java逻辑运算符之&&、|| 与&、 |的区别及应用

《Java逻辑运算符之&&、||与&、|的区别及应用》:本文主要介绍Java逻辑运算符之&&、||与&、|的区别及应用的相关资料,分别是&&、||与&、|,并探讨了它们在不同应用场景中... 目录前言一、基本概念与运算符介绍二、短路与与非短路与:&& 与 & 的区别1. &&:短路与(AND)2. &:非短

Mysql中InnoDB与MyISAM索引差异详解(最新整理)

《Mysql中InnoDB与MyISAM索引差异详解(最新整理)》InnoDB和MyISAM在索引实现和特性上有差异,包括聚集索引、非聚集索引、事务支持、并发控制、覆盖索引、主键约束、外键支持和物理存... 目录1. 索引类型与数据存储方式InnoDBMyISAM2. 事务与并发控制InnoDBMyISAM

Redis 内存淘汰策略深度解析(最新推荐)

《Redis内存淘汰策略深度解析(最新推荐)》本文详细探讨了Redis的内存淘汰策略、实现原理、适用场景及最佳实践,介绍了八种内存淘汰策略,包括noeviction、LRU、LFU、TTL、Rand... 目录一、 内存淘汰策略概述二、内存淘汰策略详解2.1 ​noeviction(不淘汰)​2.2 ​LR

StarRocks索引详解(最新整理)

《StarRocks索引详解(最新整理)》StarRocks支持多种索引类型,包括主键索引、前缀索引、Bitmap索引和Bloomfilter索引,这些索引类型适用于不同场景,如唯一性约束、减少索引空... 目录1. 主键索引(Primary Key Index)2. 前缀索引(Prefix Index /

Python爬虫selenium验证之中文识别点选+图片验证码案例(最新推荐)

《Python爬虫selenium验证之中文识别点选+图片验证码案例(最新推荐)》本文介绍了如何使用Python和Selenium结合ddddocr库实现图片验证码的识别和点击功能,感兴趣的朋友一起看... 目录1.获取图片2.目标识别3.背景坐标识别3.1 ddddocr3.2 打码平台4.坐标点击5.图

Java中实现订单超时自动取消功能(最新推荐)

《Java中实现订单超时自动取消功能(最新推荐)》本文介绍了Java中实现订单超时自动取消功能的几种方法,包括定时任务、JDK延迟队列、Redis过期监听、Redisson分布式延迟队列、Rocket... 目录1、定时任务2、JDK延迟队列 DelayQueue(1)定义实现Delayed接口的实体类 (

SpringBoot中整合RabbitMQ(测试+部署上线最新完整)的过程

《SpringBoot中整合RabbitMQ(测试+部署上线最新完整)的过程》本文详细介绍了如何在虚拟机和宝塔面板中安装RabbitMQ,并使用Java代码实现消息的发送和接收,通过异步通讯,可以优化... 目录一、RabbitMQ安装二、启动RabbitMQ三、javascript编写Java代码1、引入

shell脚本自动删除30天以前的文件(最新推荐)

《shell脚本自动删除30天以前的文件(最新推荐)》该文章介绍了如何使用Shell脚本自动删除指定目录下30天以前的文件,并通过crontab设置定时任务,此外,还提供了如何使用Shell脚本删除E... 目录shell脚本自动删除30天以前的文件linux按照日期定时删除elasticsearch索引s

PyCharm 接入 DeepSeek最新完整教程

《PyCharm接入DeepSeek最新完整教程》文章介绍了DeepSeek-V3模型的性能提升以及如何在PyCharm中接入和使用DeepSeek进行代码开发,本文通过图文并茂的形式给大家介绍的... 目录DeepSeek-V3效果演示创建API Key在PyCharm中下载Continue插件配置Con