(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

相关文章

Spring Boot集成SLF4j从基础到高级实践(最新推荐)

《SpringBoot集成SLF4j从基础到高级实践(最新推荐)》SLF4j(SimpleLoggingFacadeforJava)是一个日志门面(Facade),不是具体的日志实现,这篇文章主要介... 目录一、日志框架概述与SLF4j简介1.1 为什么需要日志框架1.2 主流日志框架对比1.3 SLF4

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

Kotlin运算符重载函数及作用场景

《Kotlin运算符重载函数及作用场景》在Kotlin里,运算符重载函数允许为自定义类型重新定义现有的运算符(如+-…)行为,从而让自定义类型能像内置类型那样使用运算符,本文给大家介绍Kotlin运算... 目录基本语法作用场景类对象数据类型接口注意事项在 Kotlin 里,运算符重载函数允许为自定义类型重

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Python中的Walrus运算符分析示例详解

《Python中的Walrus运算符分析示例详解》Python中的Walrus运算符(:=)是Python3.8引入的一个新特性,允许在表达式中同时赋值和返回值,它的核心作用是减少重复计算,提升代码简... 目录1. 在循环中避免重复计算2. 在条件判断中同时赋值变量3. 在列表推导式或字典推导式中简化逻辑

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

JAVA保证HashMap线程安全的几种方式

《JAVA保证HashMap线程安全的几种方式》HashMap是线程不安全的,这意味着如果多个线程并发地访问和修改同一个HashMap实例,可能会导致数据不一致和其他线程安全问题,本文主要介绍了JAV... 目录1. 使用 Collections.synchronizedMap2. 使用 Concurren

python中各种常见文件的读写操作与类型转换详细指南

《python中各种常见文件的读写操作与类型转换详细指南》这篇文章主要为大家详细介绍了python中各种常见文件(txt,xls,csv,sql,二进制文件)的读写操作与类型转换,感兴趣的小伙伴可以跟... 目录1.文件txt读写标准用法1.1写入文件1.2读取文件2. 二进制文件读取3. 大文件读取3.1

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

Python从零打造高安全密码管理器

《Python从零打造高安全密码管理器》在数字化时代,每人平均需要管理近百个账号密码,本文将带大家深入剖析一个基于Python的高安全性密码管理器实现方案,感兴趣的小伙伴可以参考一下... 目录一、前言:为什么我们需要专属密码管理器二、系统架构设计2.1 安全加密体系2.2 密码强度策略三、核心功能实现详解