Delphi 的操作符重载 - Record 结构体

delphi XE+中的record新特性 摘要:从Delphi2009开始,record类型支持构造函数(destructor)和析构函数(constructor),语法与类相似。record不支持继承但可重载运算符(如+、-、=等),且需显式调用构造函数。Delphi10.4+版本引入管理record功能,支持自动资源清理(RAII模式)。通过操作符重载可实现自定义类型转换和运算,如向量加减运算。相比类,record性能更优但不支持继承,适合简单数据结构封装。 阅读详情

操作符重载是语法上的一些基础用法,但之前我不太了解。最近看了下文档,写了一下测试代码,记录在这里。

基础知识

首先看这个链接:

Class Operators in Delphi

这个链接文章的作者是 Marco Cantu,一个资深的 Delphi 专家。他在这篇文章里面的代码例子:

type
  TNumber = class
  private
    FValue: Integer;
    procedure SetValue(const Value: Integer);
  public
    property Value: Integer read FValue write SetValue;
    class operator Add (a, b: TNumber): TNumber;
    class operator Implicit (n: TNumber): Integer;
end;

//---------- 上述代码的用法 ----------

a, b, c: TNumber;
...
c := a + b;
ShowMessage (IntToStr (c));

解释一下:对于 TNumber 这个东西(一个 class,一个类),这个类型的变量,可以直接用加法符号,直接相加。就是因为它有 class operator add(a, b: TNumber) 这样的代码在里面。

问题是,这段代码在我的 Delphi 10.4 CE 版上编译无法通过,IDE 提示语法错误。

我把 TNumber = class 改为 TNumber = record 结果可以编译通过。

这里的 class operator 就是对加法这个操作符,做了一个【重载】,针对这个话题,Delphi 官方的文档链接在下面:

Operator Overloading (Delphi) - RAD Studio (embarcadero.com)

上述链接的文章的标题是:Operator Overloading

我的测试代码

以下代码在 Delphi 10.4 CE 版上测试通过。

type
  TMyEvent = procedure(const i: Integer) of object;

  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Memo1: TMemo;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
    procedure DoOnEvent(const i: Integer);
    procedure DoOnEvent2(const i: Integer);
  public
    { Public declarations }
  end;

  // class operator 在 record 里面可用。
  TNumber = record
  private
    FValue: Integer;
    FValue2: Integer;
    FOnEvent: TMyEvent;

    procedure SetValue(const Value: Integer);
  public
    property Value: Integer read FValue write SetValue;
    property MyEvent: TMyEvent read FOnEvent write FOnEvent;

    class operator Add(a, b: TNumber): TNumber;
    class operator Implicit(n: TNumber): Integer;  //Implicit 这个单词:隐含的,这里的定义,是指在代码里面可以直接拿  TNumber 当作一个 Integer 用。
    class operator Explicit(i: Integer): TNumber;
  end;


var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TNumber }

class operator TNumber.Add(a, b: TNumber): TNumber;
begin
  Result.FValue := a.FValue + b.FValue;
end;

class operator TNumber.Explicit(i: Integer): TNumber;
begin
  Result.FValue := i;
end;

class operator TNumber.Implicit(n: TNumber): Integer;
begin
  Result := n.FValue;
end;

procedure TNumber.SetValue(const Value: Integer);
begin
  Self.FValue := Value;
  Self.FOnEvent(Value);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  a, b, c: TNumber;
begin
  a.MyEvent := Self.DoOnEvent;
  b.MyEvent := Self.DoOnEvent2;
  c.MyEvent := Self.DoOnEvent;

  a.Value := 2;
  b.Value := 5;
  c := a + b;

  Label1.Caption := c.Value.ToString;

  Memo1.Lines.Add(IntToStr(C));  // class operator Implicit(n: TNumber): Integer; 这句话的作用,就是 C: TNumber 可以直接当 Integer 用。
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  a: TNumber;
  i: Integer;
begin
  i := 3;
  a := TNumber(i); //class operator Explicit(i: Integer): TNumber; 这句让 a := TNumber(i) 起作用。但不能直接 a := i;

end;

procedure TForm1.DoOnEvent(const i: Integer);
begin
  Memo1.Lines.Add('Event1: ' + i.ToString);
end;

procedure TForm1.DoOnEvent2(const i: Integer);
begin
  Memo1.Lines.Add('Event2: ' + i.ToString);
end;

上述代码的解释:

1. 对于一个 Record 结构体类型来说,可以通过操作符重载的方式,把加号操作符,重新定义。也就是 TNumber 这个结构体的这部分代码:

TNumber = record
  FValue: Integer;
class operator Add(a, b: TNumber): TNumber; //重新定义了加法


//重新定义的加法的实现
class operator TNumber.Add(a, b: TNumber): TNumber;
begin
  Result.FValue := a.FValue + b.FValue;
end;

有了上述重载加法符号,则下面的代码就可以正常执行:

procedure TForm1.Button1Click(Sender: TObject);
var
  a, b, c: TNumber;
begin
  a.Value := 2;
  b.Value := 5;
  c := a + b;

  Label1.Caption := c.Value.ToString;
end;

上述代码里面,a, b, c 三个 TNmber 类型的结构体变量,可以直接用加法符号来相加!

2. 操作符里面还有两个玩意:Implicit 和 Explicit,关于它的代码如下:

TNumber = record
  private
    FValue: Integer;
  public
    class operator Implicit(n: TNumber): Integer;  
    class operator Explicit(i: Integer): TNumber;
end;


//实现代码如下
class operator TNumber.Explicit(i: Integer): TNumber;
begin
  Result.FValue := i;
end;

class operator TNumber.Implicit(n: TNumber): Integer;
begin
  Result := n.FValue;
end;

这两个 class operator 究竟是什么意思呢?用翻译软件翻译这个英文单词,也不知道它究竟是什么意思,干嘛用的。用测试代码看看它能干什么:

procedure TForm1.Button1Click(Sender: TObject);
var
  a, b, c: TNumber;
begin
  a.MyEvent := Self.DoOnEvent;
  b.MyEvent := Self.DoOnEvent2;
  c.MyEvent := Self.DoOnEvent;

  a.Value := 2;
  b.Value := 5;
  c := a + b;

  Label1.Caption := c.Value.ToString;

  // class operator Implicit(n: TNumber): Integer; 这句话的作用,就是 C: TNumber 可以直接当 Integer 用。
  Memo1.Lines.Add(IntToStr(C));
end;

对 Implicit 这个操作符的重载代码,让程序可以把这个 TNumber 结构体的变量,直接当作整数来用,把它放到 IntToStr() 函数里面,编译器不会报错,运行得到正确的结果!

继续看另外一个玩意的测试代码:

procedure TForm1.Button2Click(Sender: TObject);
var
  a: TNumber;
  i: Integer;
begin
  i := 3;

  //class operator Explicit(i: Integer): TNumber; 
  //这句让 a := TNumber(i) 起作用。但不能直接 a := i;
  a := TNumber(i);
  Memo1.Lines.Add(IntToStr(a));
end;

上述代码中,可以直接通过类型转换,把一个整数 i 变成一个 TNumber 类型的结构体!编译不会出错,执行结果正确。这个功能的实现就依靠了前面的对 Explicit 这个操作符的重载代码。

Record 结构体中的事件

一个类,可以在类定义里面,定义和事件有关的代码。然后就可以让这个类的实例对象,在需要触发某个事件的时候,触发一个事件的代码。前面我贴的完整测试代码里面,在一个 Record 结构体定义中,我也定义了一个事件变量,并且在使用一个 Record 变量实例中,给事件赋值了,测试到事件代码被执行了。

首先,我定义了一个用来做事件的方法类型:

type
  TMyEvent = procedure(const i: Integer) of object;

假设你要的事件的方法类型,Delphi 自己本身就带了,那直接用,也不用自己定义了。比如 Delphi 自己有的一个类型,是使用 Delphi 的时候最常见的类型:

TNotifyEvent = procedure(Sender: TObject) of object;

平常见到的 OnClick 啊什么的,就是这个 TNotifyEvent 类型。

然后我在这个 Record 结构体里面,定义了一个事件变量:

TNumber = record
  private
    FValue: Integer;
    FOnEvent: TMyEvent;        //事件的变量

    procedure SetValue(const Value: Integer);
  public
    property MyEvent: TMyEvent read FOnEvent write FOnEvent; //事件

    property Value: Integer read FValue write SetValue;  //属性
  end;


//给它的属性 Value 设置属性时,触发事件。

procedure TNumber.SetValue(const Value: Integer);
begin
  Self.FValue := Value;
  Self.FOnEvent(Value);
end;

这里,给一个 Record 结构体,可以有 private 和 public 关键词,也可以有 property 关键词,简直和一个类一样了。

这里的 property MyEvent: TMyEvent 就是一个事件!

使用这个事件的代码如下:

procedure TForm1.Button1Click(Sender: TObject);
var
  a, b, c: TNumber;
begin
  //结构体变量,可以有事件!
  a.MyEvent := Self.DoOnEvent; //为变量 a 的事件赋值方法;
  b.MyEvent := Self.DoOnEvent2;  //为变量 b 的事件赋值;
  c.MyEvent := Self.DoOnEvent;  //为变量 c 的事件赋值;

  a.Value := 2;
  b.Value := 5;
  c := a + b;

  Label1.Caption := c.Value.ToString;
end;


//事件方法如下:
procedure TForm1.DoOnEvent(const i: Integer);
begin
  Memo1.Lines.Add('Event1: ' + i.ToString);
end;

procedure TForm1.DoOnEvent2(const i: Integer);
begin
  Memo1.Lines.Add('Event2: ' + i.ToString);
end;

上述代码的执行结果是在 Memo1 里面看到两个不同的方法被执行了。

总结

操作符重载

可以给 Record 结构体类型,重载操作符,比如加号,就是 add,重新用代码定义。还有很多其它操作符,也可以做重载,看本文前面的官方文档链接。从我自己写的这个测试代码来看,它可以让我们在使用 Record 结构体的时候,可以直接写 c := a + b; 这样的代码,如果没有重载 add 这个操作符号,可能就要这样写:

var
  a, b, c: TNumber;
begin
  a.Value := 3;
  b.Value := 5;
  c.Value := a.Value + b.Value;

  //如果没有给 TNumber 重载 add 操作符,就不能写以下代码:
  c := a + b;
end;

那么,看起来,这里的作用就是让以后使用 TNumber 这个结构体的时候,简单一点,少写一些代码。还有没有其它的作用?需要继续尝试才知道。或者有文档资料介绍。

属性和事件

Record 类型,可以和 class 类型一样,可以定义属性和事件!

当然,Record 结构体类型,也可以有方法和函数。

那么,一个 Record 结构,和一个类,有什么区别呢?需要思考。

Delphi语言的语法糖 语法糖是编程语言中一种看似多余的功能,它并不增加语言的表达能力,却使得某些操作更加简洁。例如,在许多语言中,使用操作符重载可以以更加直观的方式实现特定的功能。语法糖的本质是为了提高代码的可读性,使得程序员可以用一种更自然的方式表达意图。在Delphi中,语法糖的引入不仅提升了代码的可维护性,也让语言本身更加灵活和强大。Delphi语言的语法糖特性为程序员提供了一种更加友好的开发体验。通过简化语法的使用,Delphi允许开发者更专注于业务逻辑的实现,并提高了代码的可读性与可维护性。 阅读详情

相关推荐

【Delphi 基础知识 9】Record类型定义的特点

本文主要详细讲解了记录类型(record)。

记录日常技术经验 1318

Delphi中record的使用

在Delphi中的Record类型中,与之C语言对应的即是结构体类型(struct),也可能是为了符合C语言或C++程序员的习惯,对于它在Delphi中的应用存在的一些问题进行初步的说明。在Delphi中的记录体类型有两种方式定义 Type RecTest = record (packed) ID :integer; Name :s...

weixin_34356555的博客 463

【Delphi 基础知识 10】class operator重载运算符的使用

重载运算符只能用在Record记录类型中,这个特性是从 Delphi 2005 版本开始引入的,实际就简化了一些运算处理代码,不使用这种语法规则也是可以的,但是别人的代码如果使用了我们得能看的懂。,你可以为你的Record记录类型中自定义运算符,使得Record能够像内置类型一样支持各种运算符操作。这使得你可以更灵活地定义类的行为,使其更符合特定的需求。具体的重载运算符类型取决于你的类的用途和设计。以下是一个简单的示例,演示了如何在Delphi中使用。是一种用于重载类运算符的语法。等,用于自定义类型转换。

记录日常技术经验 719

Delphi语法(八)运算符重载

Delphi语法第九章 运算符重载

ForAnnuus的博客 674

【Delphi 基础知识 11】重载函数的使用

总体而言,重载函数的使用范围很广泛,可以在许多不同的编程场景中提高代码的可读性和灵活性。字符串处理: 在字符串处理中,可能会有不同版本的函数,用于连接、比较、格式化等,以适应不同的参数类型或处理需求。重载函数可使代码更通用。容器类和集合操作: 在处理数组、列表、集合等数据结构时,重载函数可以处理不同类型的元素或执行不同的操作。API设计: 在设计类库或API时,重载函数可以提供更自然、直观的接口,以适应不同的使用情境。图形编程: 在图形编程中,可以使用重载函数来处理不同类型的图形对象,如圆形、矩形等。

记录日常技术经验 700

8155平台multi-display(多屏显示)原理与配置

8155平台多屏互动原理与配置

漂流瓶の海岸 1608

Delphi结构体的扩展,可以自动初始化,反初始化,自定义拷贝函数.

转载:http://www.raysoftware.cn/?p=518&utm_source=tuicool 恭贺Delphi XE7诞生,Delphi XE7在编译器内部集成了我之前所实现的动态数组扩展.http://www.raysoftware.cn/?p=278现在有一个更悠久的历史需求,在QC的Delphi板块上置顶了好多年.官方一直没有实现.http://qc.embarca...

weixin_30915951的博客 104

利用CubeMX复现正点原子TFTLCD驱动例程

①准备delay.c、delay.h、sys.c和sys.h四个文件。FMC的工作原理暂时先欠着,先记录一下CRUD的过程。这里我们使用的是BANK1 的第一个分区。点击 Configuration->FMC。②把fmc自动生成的代码注释掉一部分。配置参数如下图 17.5.1。③这个printf语句要屏蔽掉。选项卡之下配置相关参数。④整体代码,按需裁剪。

qq_59757948的博客 1613

Delphi-记录类型record的使用

1-案例代码(控制台应用程序) program Project1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; // 定义一个结构类型 type Tpeople = record Name :string; Age:Integer; Sex:string; end; var people:Tpeople; begin with people do begin Name := '工藤新一'; A

m0_52389829的博客 3188

SpotBugs使用

spotbugs命令行参数解析

javajingling的专栏 2948

Matplotlib字体警告终结者:为什么总提示DejaVu Sans?5种场景解决方案大全

本文深入解析Matplotlib中常见的DejaVu Sans字体警告问题,并提供5种典型场景的完整解决方案。从理解字体系统的三层架构和缓存机制,到解决中文显示、远程服务器部署、TeX渲染、缓存优化及生产环境配置等实际问题,帮助开发者彻底摆脱字体警告困扰,实现稳定可靠的数据可视化。

view3的博客 502

[Delphi][Record]构造自己的万用数据类型

Delphi中对Record类型的操作符重载

学习到死 754

SystemVerilog从入门到实战

SystemVerilog复合数据类型概述 SystemVerilog增强了Verilog的数据建模能力,提供多种复合数据类型: 数组类型:包括定宽数组(固定大小)、动态数组(运行时分配)和多维数组,支持高效索引访问。 队列:结合数组和链表特性,支持两端快速插入/删除操作,提供push/pop等方法。 关联数组:键值对存储结构,支持稀疏数据存储和快速查找,提供exists/delete等方法。 结构体:组合不同类型数据成员,支持打包(packed)形式以优化存储空间。 枚举类型:为数值赋予语义名称,支持状态

2301_79143213的博客 1227

delphi 中record 的类操作符重载简介

  今天简单介绍一下 delphi 中record 的类操作符重载使用,就是如何 实现 record 之间的简单操作。 关于类操作符重载 ,大家可以看 官方的文档。   Delphi allows certain functions, or "operators", to be overloaded within record declarations. The name of the o...

weixin_34341229的博客 402

《拉依达的嵌入式\驱动面试宝典》—计算机硬件篇(一)

《拉依达的嵌入式\驱动面试宝典》 整合了所有我认为可能遇到的技术面试问题。所有问题及其答案均是我个人学习后查阅资料总结,每个回答都做了仔细的分析,在嵌入式及其驱动面试相关问题解析做到全网独一无二。学习或者转行到嵌入式、驱动开发领域学习的不二之选

拉依达不拉跨的博客 768

SAP-RPT-1 深度解读:面向企业表格数据的 rapid one

摘要: SAP在TechEd 2025大会上推出面向企业结构化数据的SAP-RPT-1(Relational Pretrained Transformer),旨在通过in-context learning直接预测表格数据中的缺失值,无需传统机器学习流程。与LLM不同,RPT专为业务表格设计,支持实时预测(如交货延迟、回款风险等)。提供Small(高吞吐)、Large(高精度)和开源版本,用户可通过无代码Playground(上传CSV并用[PREDICT]标记目标列)或Python API快速验证。典型场景

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 237

Delphi的运算符重载

使用Delphi编写游戏,唯一没有C++方便的就是不支持运算符重载。当你编写有关向量或者矩阵计算的程序时,不支持运算符重载的Delphi使用起来是很费劲的。但是Delphi 2006改变了这种局面,新的Delphi内核已经支持运算符重载了!本文将介绍如何使用Delphi的运算符重载功能 注意:只有Delphi 2006 和 免费版的 Turbo Delphi 支持这一功能! Delphi f...

weixin_30252709的博客 167

Pointnet++改进90:2025最新改进模块-EVA模块

本教程提出了一种改进PointNet++特征提取模块的方法,通过在PointNetSetAbstraction模块中加入NAMAttention注意力机制,显著提升了模型性能。具体改进包括:1)新建eva.py文件,实现了包含SDLSKA、CKS等关键组件的EVA模块;2)在pointnet2_utils.py中添加Conv和PointNetSetAbstractionAttention类,整合注意力机制;3)修改pointnet2_sem_seg.py模型结构。这种改进方法降低了实现难度,同时保持了33F

AIcurator的博客 361

delphi 运算符重载

譬如上面的 record 可以这样声明: type TMyRec = record name: string; age: Word; class operator GreaterThan(a,b: TMyRec): Boolean; end; 还得有方法的实现(遗憾的是有些不能用 Ctrl+Shift+C 自动建立, 那就复制吧): c...

weixin_30544657的博客 175

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

DELPHI8操作符重载的例子

unit WinForm;interfaceuses  System.Drawing, System.Collections, System.ComponentModel,  System.Windows.Forms, System.Data;type  TWinForm = class(System.Windows.Forms.Form)  {$REGION Designer Ma

wr960204(武稀松)的专栏 1505

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

delphi2006语言新特性:Record类型高级用法

delphi语言在传统的Records类型的基础上增加了许多像类一样的高级功能,如:Records可以有属性和方法(包括构造constructors),类属性,类方法,类静态字段和内嵌类型。下面这个示例演示定义一个功能像类一样的Records: typeTMyRecord = recordtypeTInnerColorType = Integer;varRed: Integer;class va...

weixin_30785593的博客 373

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

上一篇: 多线程,主线程的概念以及在 Delphi 的新语法中的代码写法
下一篇: Skia4Dephi 的 Demo 程序界面架构分析
pcplayer
博客等级 码龄26年 633粉丝 284原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值