(delphi11最新学习资料) Object Pascal 学习笔记---第10章第2节(published访问说明符)

10.2 published访问说明符

​ 除了 public、protected 和 private 访问指令(以及不太常用的strict private 和strict protected)之外,Object Pascal 语言还有一个非常特别的访问指令,叫做 published。published属性(或字段或方法)不仅可以像public属性一样在运行时可用,而且还能生成可查询的扩展运行时信息(extended RTTI)。

​ 事实上,在编译型语言中,编译后的符号由编译器处理并且在测试应用程序时调试器可以使用,但在运行时一般不会留下这些符号。换句话说(至少在早期的 Object Pascal 语言中是这样),如果一个类有一个名为 Name 的属性,你可以在代码中使用它来与类交互,但这种交互会被转换成数字地址,而源代码级别的标识符概念在运行时就不存在了,这意味着没有办法找出一个类是否有与给定字符串(如 “Name”)相匹配的属性标识符。

**注意:**Java 和 C# 语言都是采用了复杂虚拟执行环境(虚拟机)的编译型语言,因此,它们通过一种称为反射的概念拥有大量的运行时信息。Object Pascal 语言早在其他编译语言之前就有了基本的反射(通过published关键字),而之后随着语言的演变又引入了更多的反射或者说扩展的RTTI。本章将探讨与published关键字相关的基本 RTTI,第 16 章将探讨扩展反射。

​ 为什么需要这些关于类的额外信息呢?这些信息是Object Pascal库所依靠的组件模型和可视化编程模型的基础之一。其中一些信息在开发环境中进行设计时使用,以填充“对象检视器”(Object Inspector)中组件提供的属性列表。这不是一个硬编码的列表,而是通过运行时检查编译后的代码中包含的额外运行时类型信息(RTTI)数据生成的。

​ 另一个例子,可能有点复杂,现在不太适合深入讨论的是创建FMX和DFM文件以及任何附带的可视化窗体背后的流式传输机制。流式传输将仅在第18章中介绍,因为它更多地属于运行时库而不是核心语言。

​ 总结这一概念:当您编写供自己或其他人在开发环境中使用的组件时,使用published关键字是重要的。通常,组件的published部分仅包含属性,但是窗体类还会使用published字段和方法,这些将在稍后介绍。

10.2.1 设计时属性

​ 在本章的前面部分,我们已经了解到属性在类的数据封装中扮演着重要角色。它们还在启用可视化开发模型方面起着基础性作用。事实上,您可以编写一个组件类,将其提供给开发环境,通过将其添加到窗体或类似的设计界面来创建对象,并使用“对象检视器”与其属性进行交互——这是可视化编程环境提供的工具,让您能够访问属性。并非所有属性都可以在这种情况下使用,只有那些在组件类中标记为"published"的属性才能够。这就是为什么Object Pascal程序员区分设计时属性运行时属性

​ 设计时属性是在类声明的"published"部分中声明的,可以在IDE中以及在代码中使用。在类的"public"部分中声明的任何其他属性都不可在设计时使用,只能在代码中使用,通常被称为仅在运行时可用的属性。

​ 换句话说,在设计时,您可以使用“对象检视器”查看并更改published属性的值。在运行时,您可以通过完全一样的方式在代码中读取值或写入值的方式访问另一个类的任何public或published属性。

​ 并非所有类都有属性。属性存在于组件和TPersistent类的其他子类中,因为属性通常可以被流式传输并保存到文件中。事实上,窗体文件只不过是窗体上组件的published属性的集合。

​ 更准确地说,要在一个类中支持published节(section),你不需要继TPersistent 类,但你需要使用$M编译器指令编译这个类。每一个使用该指令编译的类,或者从使用该指令编译的类派生出来的类,都支持published节。由于 TPersistent 是使用此设置编译的,那么其任何派生类都支持此功能。

注意 下面关于默认可见性和自动 RTTI 的两节将进一步介绍$M 指令和published关键字的更多信息。

10.2.2 published属性与窗体

​ 当IDE(集成开发环境)生成一个表单时,它会把表单上组件和方法的定义放在类的初始部分,也就是public和private关键词之前。这些初始部分的字段和方法就是已发布的属性。

​ 尽管published属性是全局可见的,但这并不意味着进行全局访问是一个好主意。这意味着您必须特别注意您正在访问的全局属性(正如在前面关于向表单添加属性的部分所讨论的)。此外,当在组件类的元素之前指定显式访问指令时,默认访问级别是published。

注意 更准确地说,只有当类是在使用$M+编译器指令的情况下编译的,或者是从使用$M+编译器指令编译的类派生的,published才是默认关键字。由于TPersistent类中使用了该指令,因此库的大多数类和所有组件类默认是published。然而,非组件类(如TStream和TList)是在使用$Mand指令的情况下编译的,它们默认是public可见性。

​ 这里是一个例子:

type
	TForm1 = class(TForm)
		Memo1: TMemo;
		BtnTest: TButton;

​ 分配给任何事件的方法都应该是published方法,窗体中与您的组件相对应的字段应该也是published,以便能够自动与窗体文件中描述的对象连接并随着窗体一起创建。

​ 只有窗体声明初始published部分中的组件和方法才会出现在对象检查器中(在窗体组件列表中或当您选择事件下拉列表时显示的可用方法列表)。

​ 为什么类的组件应该使用published段进行声明,而它们可以是私有的并更好地遵循OOP封装规则?原因在于这些组件是通过读取其流式表示而创建的,但一旦创建,就需要分配给相应的窗体字段。

​ 这是通过RTTI完成的,RTTI由published字段生成。

注意,从技术上讲,并不是真的强制要求为组件使用published字段。通过将组件设为私有,可以让代码更加符合面向对象设计原则。然而,这样做需要额外的运行时代码。我将在本章的最后一节“RAD和OOP”中对此进行进一步解释。

10.2.3 RTTI自动生成

​ Object Pascal编译器另一个特殊的行为是,如果你在一个不是从TPersistent类继承的类中添加published关键字,编译器将自动启用RTTI生成,自动添加{$M+}编译指令。假设你有这样的一个类:

type
	TMyTestClass = class
	private
        FValue: Integer;
        procedure SetValue(const Value: Integer);
    published
    	property Value: Integer read FValue write SetValue;
    end;

​ 编译器将发出如下警告:

[dcc32 Warning] AutoRTTIForm.pas(27): W1055 PUBLISHED caused RTTI ($M+)
to be added to type 'TMyTestClass'

​ 幕后所发生的是,编译器会自动在代码中注入{$M+}指令,正如你在AutoRTTI示例中所看到的那样,该示例包含了上面的代码。在这个程序中,你可以编写以下代码,该代码可以动态地访问属性(使用老式的System.TypInfo单元):

uses
	TypInfo;
	
procedure TFormAutoRtti.BtnTestClick(Sender: TObject);
var
	Test1: TMyTestClass;
begin
	Test1 := TMyTestClass.Create;
	try
		Test1.Value := 22;
		Memo1.Lines.Add(GetPropValue(Test1, 'Value'));
	finally
		Test1.Free;
	end;
end;

注意 尽管我偶尔会使用TypInfo单元及其定义的GetPropValue等函数,但RTTI访问的真正威力是由更现代的RTTI单元及其对反射的大量支持提供的。考虑到这是一个相当复杂的话题,我觉得应该单独为它写一章,并且还要区分现代Object Pascal支持的两种RTTI风格。

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

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

相关文章

[iOS]CocoaPods安装和使用

1.了解brew、rvm、ruby、gem、cocaspods之间的关系 在 macOS 环境中,Brew、RVM、Ruby、Gem 和 CocoaPods 之间存在以下关系: Homebrew (Brew):Homebrew 是 macOS 上的包管理器,用于安装和管理各种开源软件包。它使您能够轻松地从…

Windows 本地直接使用 SSH,SFTP 以及 SFTP下载文件到 Windows/mac 本地或上传(没有客户端时)

windows 本地打开 ssh 以及 sftp 等的方式 1.win(windows图标那个键) r 直接搜 然后从打开的位置运行 如果是打开 sftp 前面的 ssh 换一下成sftp 就行 直接从地址栏输入也可以直接转过去 通过 windows 的工具直接访问 sftp 后将文件下载到自己的windows 或 mac 上 先通过…

微软在汉诺威工业博览会上推出新制造业Copilot人工智能功能,强化Dynamics 365工具集

在近日于德国汉诺威举行的盛大工业博览会上,微软向全球展示了其最新推出的制造业人工智能功能,这些功能以Dynamics 365工具集为核心,旨在通过先进的AI技术为制造业带来前所未有的变革。 此次推出的新功能中,最为亮眼的是支持AI的…

Linux之ebpf(1)基础使用

Linux之ebpf(1)基础使用 Author: Once Day Date: 2024年4月20日 一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦… 漫漫长路,有人对你微笑过嘛… 全系列文章可以参考专栏:Linux基础知识_Once-D…

Linux系统网络---DNS域名解析服务

目录 一、DNS的简介 DNS系统的分布式数据结构👇 DNS系统类 两种查询方式 二.正向解析实验 1.先关闭防火墙、selinux 2.安装bind 3.查看配置、修改配置 4.修改区域配置文件 正向解析👇 反向解析👇 5.修改 正向解析&#x1f…

装饰品模式介绍

装饰器模式是一种结构型设计模式,它允许用户在不改变现有对象的情况下向一个对象添加新的功能。在 Java 中,装饰器模式经常用来动态地给对象添加额外的行为,如日志记录、事务管理、安全检查等。 装饰器模式涉及四个主要角色:组件&…

公司服务器中的kafka消息中间件挂了,我是如何修复的?

今天的公司的system系统服务在运行过程中,提示连接不上kafuka的消息中间件。但是负责kafka的同事已经离职了,询问公司开发也不知道如何处理,我是如何重启kafka消息中间件使system系统服务正常运行? 查看kafka的安装位置 在下面的…

【C++】---STL之list的模拟实现

【C】---STL之list的模拟实现 一、list模拟实现思路二、结点类的实现三、list迭代器的实现1、ListIterator类2、构造函数3、operator*运算符重载5、operator->运算符重载6、operator!运算符重载7、operator运算符重载8、前置9、后置10、前置--11、后置-- 四、lis…

从零开始安装 stable diffusion webui v1.9.3 (windows10)

从零开始安装 stable diffusion webui v1.9.3 (windows10) CUDA 安装 CUDA 12.1 | https://developer.nvidia.com/cuda-toolkit-archive CUDNN 8.x | https://developer.nvidia.com/rdp/cudnn-archive 安装路径 F:/CUDA/v12.1 安装git git官网 | https://git-scm.com/ 安…

Linux文件/目录高级管理一(头歌实训)

目录 任务描述 相关知识 Linux修改文件权限命令 Linux修改所有者权限 Linux修改同组用户权限 Linux修改其他用户权限 编程要求 任务描述 相关知识 Linux修改目录权限命令 Linux修改所有者权限 Linux修改同组用户权限 Linux修改其他用户权限 编程要求 任务描述 相…

3.1设计模式——Chain of Responsibility 责任链模式(行为型)

意图 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这些对象练成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。 实现 其中 Handle定义一个处理请求的接口:(可选…

【线段树 区间位运算模板】3117划分数组得到最小的值之和

本文涉及知识点 线段树 区间位运算模板 LeetCode3117. 划分数组得到最小的值之和 给你两个数组 nums 和 andValues,长度分别为 n 和 m。 数组的 值 等于该数组的 最后一个 元素。 你需要将 nums 划分为 m 个 不相交的连续 子数组,对于第 ith 个子数组…

机器视觉系统-工业光源什么是低角度打光方式

光路描述&#xff1a;光线与水平面角度 <45称为低角度光。 效果分析&#xff1a;低角度照射&#xff0c;被侧物表面平整部分的反射光无法进入入镜头&#xff0c;图像效果表现为灰度值较低&#xff1b;不平整部分的反射光进入镜头&#xff0c;图像效果表现为灰度值较高。 主要…

【白盒测试】单元测试的理论基础及用例设计技术(6种)详解

目录 &#x1f31e;前言 &#x1f3de;️1. 单元测试的理论基础 &#x1f30a;1.1 单元测试是什么 &#x1f30a;1.2 单元测试的好处 &#x1f30a;1.3 单元测试的要求 &#x1f30a;1.4 测试框架-Junit4的介绍 &#x1f30a;1.5 单元测试为什么要mock &#x1f3de;️…

Transformer step by step--Positional Embedding 和 Word Embedding

Transformer step by step往期文章&#xff1a; Transformer step by step--层归一化和批量归一化 要把Transformer中的Embedding说清楚&#xff0c;那就要说清楚Positional Embedding和Word Embedding。至于为什么有这两个Embedding&#xff0c;我们不妨看一眼Transformer的…

7.MyBatis 操作数据库(初阶)

文章目录 1.什么是MyBatis2.为什么要学习 MyBatis&#xff1f;3.通过spring框架创建MyBatis项目3.1使用MyBatis查询数据库3.2 mysql连接不上报错解决方法 4.MyBatis的基础操作4.1企业建表规范&#xff1a;4.2MyBatis基本实现4.3单元测试4.4使用MyBatis可能遇到的问题4.5配置MyB…

Docker镜像的创建 和 Dockerfile

一. Docker 镜像的创建 创建镜像有三种方法&#xff0c;分别为基于已有镜像创建、基于本地模板创建以及基于 Dockerfile 创建。 1 基于现有镜像创建 &#xff08;1&#xff09;首先启动一个镜像&#xff0c;在容器里做修改docker run -it --name web3 centos:7 /bin/bash …

CentOS8/RHEL8 root密码破解

我们知道root是CentOS8/RHEL8系统的管理员用户&#xff0c;一般情况下&#xff0c;我们是不会把其密码忘记的&#xff0c;如果万一忘记了&#xff0c;如果破解root密码呢&#xff0c;今天就为大家详细讲讲。 1.CentOS8/RHEL8 root密码破解 1.默认安装及默认配置情况下&#x…

如何申请免费SSL证书,把网站升级成HTTPS

HTTPS&#xff08;Hyper Text Transfer Protocol Secure&#xff09;是一种用于安全数据传输的网络协议&#xff0c;它可以有效地保护网站和用户之间的通信安全。然而&#xff0c;要使一个网站从HTTP升级到HTTPS&#xff0c;就需要一个SSL证书。那么&#xff0c;如何申请免费的…

批量归一化(部分理解)

目的与疑惑 在深度学习中&#xff0c;每层输入数据的分布可能因为前一层参数的微小变动而有较大变化&#xff0c; 这种现象称为内部协变量偏移&#xff08;Internal Covariate Shift&#xff09;。 批量归一化通过规范化层输入来减少内部协变量偏移&#xff0c;使网络更稳定&a…