delphi 操作符重载

In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy required) or matrix math.  Since I rarely have need for either, operator overloading has remained one of those areas that I thought would be an interesting area to try to get into.

在我的编程生涯中,我很少遇到操作员重载对我的工作有用的情况。 通常情况下,这些情况涉及的数学要么是数量过多(数十万个数字或所需的精度),要么是矩阵数学。 由于我几乎不需要二者之一,因此操作员重载一直是我认为将成为有趣的领域之一。

I recently had another coding requirement.  I mention it here because that need collided with the idea of operator overloading to make me consider operator overloading for an entirely new reason (to me).  I am writing a language parser.  This involves reading in characters one at a time and breaking them into tokens.  A big part of my coding along these lines, in the past, has been to make use of a Set Of Char.  This allows me to write very naturally flowing, easy to ready code such as:

我最近有另一个编码要求。 我在这里提到它是因为这种需要与运算符重载的思想相冲突,这使我出于全新的原因考虑运算符重载(对我而言)。 我在写语言解析器。 这涉及一次读取一个字符并将其分解为令牌。 过去,我沿这些方面进行编码的很大一部分是利用Set Of Char。 这使我可以编写非常自然的,易于编写的代码,例如:

function SkipWhiteSpace(var C : PChar) : boolean;
constWhiteSpace = [#9, #10, #13, ' '];beginWhile (C^ <> #0) and (C^ in WhiteSpace) doinc(C);Result := C^ <> #0;  //fail if at the end
end;

This is simply an example of how things might have looked.  There are several things wrong with this code since Delphi 2009 introduced Unicode strings.

这只是情况看起来的一个例子。 自从Delphi 2009引入Unicode字符串以来,此代码存在一些问题。

If you attempt to use a set of character to do the same kind of test on characters in the newer versions of Delphi you get a warning:

如果尝试使用一组字符对较新版本的Delphi中的字符进行相同类型的测试,则会收到警告:

W1050 WideChar reduced to byte char in set expressions.  Consider using 'CharInSet' function in 'SysUtils' unit.

W1050 WideChar在集合表达式中减少为字节char。 考虑在“ SysUtils”单元中使用“ CharInSet”功能。

To avoid this, you could change:

为避免这种情况,您可以更改:

(C^ in WhiteSpace)
(CharInSet(C, WhiteSpace))

Different varieties of Unicode strings may contain characters that are 1-4 bytes wide.  For this reason, instead of

不同种类的Unicode字符串可能包含1-4字节宽的字符。 因此,代替

Inc(C);
C := StrNextChar(C);

The code could also have been written to make use of streams, keep in mind this is written to focus on the issue at hand.  While there are valid concerns about the code, try to keep focused on where I am heading and leave the analysis for later.

也可以编写代码来利用流,请记住,编写此代码的重点是当前的问题。 尽管对代码存在真正的担忧,但请尝试专注于我要去的地方并将分析留给以后使用。

A Delphi set type is limited to 256 elements due to the fact that each element is represented by one bit (resulting in a 32 byte type).  With 65,536 possibilities in a 2 byte character this would result in an 8k set variable since a set requires all of the space, even when empty.

由于每个元素都由一位表示(导致32字节类型),因此Delphi集类型限制为256个元素。 在2字节字符中有65,536种可能性,这将导致8k的set变量,因为set需要所有空间,即使是空的也是如此。

While the new notation works, I find it makes the code less natural to read.  Doing things the old way will generate warnings, you could ignore those, it also limits the sets to using Ansi (8 byte) characters.  I suppose I am like most people in that I wanted to have my cake and eat it too.

尽管新的符号有效,但我发现它使代码的可读性降低。 用旧的方式处理会生成警告,您可以忽略这些警告,这也将设置限制为使用Ansi(8字节)字符。 我想和大多数人一样,我也想吃蛋糕。

To that end I decided to use operator overloading to create a new kind of set.  The idea was to use a record that stores a string containing the characters that are in the set while allowing it to use the normal set operations.  To start with you declare a normal record type, in this case I chose not to use the usual capital T to start the name since this is intended to be a base type and is not a class.

为此,我决定使用运算符重载来创建一种新的集合。 想法是使用一条记录,该记录存储一个字符串,该字符串包含集合中的字符,同时允许它使用常规的集合操作。 首先,您声明一个正常的记录类型,在这种情况下,我选择不使用通常的大写字母T来开头名称,因为它旨在作为基本类型而不是类。

typeWideCharSet = recordChars : string;class operator Add(a, b: WideCharSet): WideCharSet;class operator Implicit(a : WideCharSet) : string;class operator Implicit(a : string) : WideCharSet;end;

I started by using a member variable called Chars as a string to hold my list of characters in my set.  The implicit class operators allow me to assign back and forth between a string and a WideCharSet.  I decided to start with the Add class operator as my first test.  When assigning from a string I did not want to just set a string of characters into the Chars member variable.  I wanted to assume I was assigning a string containing something like a normal set declaration.  In this case, to make it easier to work with, I allowed the user to denote characters with single or double quotes.  Here is the code for the Implicit conversion from string to WideCharSet the full source code will be at the end of the article so, for now, don't worry about any missing code.

我首先使用一个称为Chars的成员变量作为字符串来保存我的字符集。 隐式类运算符允许我在字符串和WideCharSet之间来回分配。 我决定从Add类运算符开始,这是我的第一个测试。 从字符串分配时,我不想仅将字符字符串设置为Chars成员变量。 我想假设我正在分配一个字符串,其中包含类似正常set声明的内容。 在这种情况下,为了简化操作,我允许用户用单引号或双引号表示字符。 这是从字符串到WideCharSet的隐式转换的代码,完整的源代码将在本文的结尾,因此,现在,不必担心缺少任何代码。

class operator WideCharSet.Implicit(a : string) : WideCharSet;
varI : integer;C, D, E : Char;beginResult.Chars := '';//have to have at least []assert(Length(a) >= 2, 'Invalid string used in convert to SetOfWideChar');I := 1;SkipWhiteSpace(a, I);assert(a[I] = '[', 'Invalid string used in convert to SetOfWideChar, ' +'missing opening square bracket');inc(I);while (I < Length(a)) and (a[I] <> ']') dobeginC := ReadChar(a, I);SkipWhiteSpace(a, I);if a[I] = '.' thenbegininc(I);if I > Length(a) thenraise Exception.Create(InvalidSetOfWideCharString);if a[I] <> '.' thenraise Exception.Create(InvalidSetOfWideCharString);inc(I);D := ReadChar(a, I);for E := C to D doInsertSorted(E, Result.Chars);endelseInsertSorted(C,Result.Chars);if a[I] = ',' thenbegininc(I);if I > Length(a) thenraise Exception.Create(InvalidSetOfWideCharString);end;end;Assert(I <= Length(A), InvalidSetOfWideCharString);Assert(a[I] = ']', InvalidSetOfWideCharString);
end;

There is quite a bit to talk about in this method.  I used assertions to enforce the style of the string passed into the conversion routine, that way they could be compiled out easily.  I included the skipping of white space to make it more friendly for developers to use.  Keep in mind that this is a first attempt.  I may change the assertions to exceptions if I find that to be more useful in some situations.

这种方法有很多要讨论的地方。 我使用断言来强制传递到转换例程中的字符串的样式,以便可以轻松地将它们编译出来。 我包括跳过空格,以使其对开发人员更加友好。 请记住,这是第一次尝试。 如果我发现断言在某些情况下更有用,则可以将其更改为异常。

I am doing some parsing in this method.  This allows me to be flexible regarding the precise format of the string being passed in.  To that end the class includes methods such as SkipWhiteSpace and ReadChar.  SkipWhiteSpace just moves past any spaces, tabs, carriage returns, and line feeds.  ReadChar does a bit more than it might seem.  It reads in the definition of a character as defined in a string.  This means either a single character in quotes, a # followed by a decimal number, or #$ followed by a hex definition.  I later realized that just adding the characters to the end of the Chars member variable would not allow me to compare sets.  Realizing this, I added the method InsertSorted.  If all of the characters are added in a sorted manner then, no matter how the set was built, comparisons should work accurately.

我正在这种方法中进行一些解析。 这使我可以灵活地处理传入的字符串的确切格式。为此,该类包括诸如SkipWhiteSpace和ReadChar之类的方法。 SkipWhiteSpace只是移过任何空格,制表符,回车符和换行符。 ReadChar的作用超出了看起来。 它读取字符串中定义的字符的定义。 这意味着要么用引号引起来,要么在#号后面加上一个十进制数字,要么在#$后面加上一个十六进制定义。 后来我意识到,仅将字符添加到Chars成员变量的末尾将不允许我比较集合。 意识到这一点,我添加了方法InsertSorted。 如果所有字符都按排序方式添加,则无论集合如何构建,比较都应正确进行。

Of course I could not define the class to accept strings in and not allow the set to be assigned to a string.  This assignment would require the parsing of the current set of characters to create a minimal definition for the set.  Here is the code for the implicit assignment of a WideCharSet to a string.

当然,我无法定义该类以接受字符串,也不允许将集合分配给字符串。 此分配需要解析当前字符集,以为该字符集创建最小定义。 这是将WideCharSet隐式分配给字符串的代码。

class operator WideCharSet.Implicit(a : WideCharSet) : string;
varLine : string;I : integer;FirstChar, LastChar : Char;Start : integer;R1, R2 : string; //possible range representations for charactersbeginLine := '';{Start at the first character and see how far we can go until we run into anon sequential character}I := 1;While I < Length(a.Chars) dobeginStart := I;FirstChar := a.Chars[I];repeatinc(I);until (I > Length(a.Chars)) or(ord(a.Chars[I]) <> Ord(FirstChar) + I - Start);LastChar := a.Chars[Pred(I)];if Line <> '' thenLine := Line + ', ';R1 := CharToStringRep(FirstChar);Line := Line + R1;if I > Start + 1 thenbeginR2 := CharToStringRep(LastChar);Line := Line + '..' + R2;end;end;Result := '[' + Line + ']';
end;

The only piece of this code I would think might need some extra explanation is CharToStringRep.  Not all characters are legible or identifiable as they are.  Some work much better as a literal numeric definition.  This function returns the character as it should be represented.  The first part inside the loop is used to find the end of a run of characters.  If no run is found then the character is added to the line.  If a run was found then it adds the first character, '..' and the last character to the line.  The process is repeated until all characters have been accounted for.

我认为这段代码中唯一需要做一些额外的解释的就是CharToStringRep。 并非所有字符都一样清晰可辨。 有些可以作为文字数字定义更好地工作。 此函数返回应表示的字符。 循环内部的第一部分用于查找字符序列的结尾。 如果找不到运行,则将字符添加到行中。 如果找到运行,则将第一个字符“ ..”和最后一个字符添加到该行。 重复该过程,直到已考虑所有字符。

Next I wanted to be able to test for membership with the IN operator.

接下来,我希望能够使用IN运算符测试成员资格。

class operator WideCharSet.In(a : Char; b : WideCharSet) : Boolean;
beginResult := SortedPos(a, b.Chars) <> 0;
end;

While I could have used the Pos function I thought it made more sense to use the same CharSearch function I use when adding to a set.  To that end I added the SortedPos function which acts just like the Pos function except it works on sorted strings of characters, using a binary search.  On large sets it should be a lot faster.  On smaller sets it should be similar speed.  If you know that your code will only be using extremely small sets you might want to switch it to use the Pos function.  Since the CharSearch function is intended to return either the index of the character, or the index of where it should be inserted, the function needed to take a couple of extra precautions (checking the the index was not past the end of the string, and that it matched).

虽然本可以使用Pos函数,但我认为使用与添加到集合中时相同的CharSearch函数更有意义。 为此,我添加了SortedPos函数,该函数的功能类似于Pos函数,只是它使用二进制搜索在排序的字符串上起作用。 在大型机器上,它应该快得多。 在较小的机器上,其速度应该相似。 如果您知道代码将仅使用极小的集合,则可能需要将其切换为使用Pos函数。 由于CharSearch函数旨在返回字符的索引或应插入字符的索引,因此该函数需要采取一些额外的预防措施(检查索引是否未超过字符串的末尾,以及匹配)。

At this point I can already do some basic code using my new type.

至此,我已经可以使用新类型执行一些基本代码了。

Procedure MyTest;
varNumeric : WideCharSet;WhiteSpace : WideCharSet;C : Char;beginWhiteSpace := '[#9..#10, #13, " "]';Numeric := '["0".."9"]';C := '6';if C in WhiteSpace thenbegin//obviously notend;if C in Numeric thenbegin//Bingoend;
end;

Here you can see assignment from strings as well as tests for membership.

在这里,您可以查看字符串分配以及成员资格测试。

From this point, the remainder of the work is in assigning more of the operator overloading class methods.  The ones we still need in order to do most of the same work as a Delphi set of char would be:

从这一点出发,剩下的工作是分配更多的运算符重载类方法。 为了完成与Delphi字符集相同的大部分工作,我们仍然需要以下这些:

    class operator Add(a, b: WideCharSet): WideCharSet;class operator Subtract(a, b: WideCharSet): WideCharSet;class operator Multiply(a, b : WideCharSet) : WideCharSet;class operator Equal(a, b: WideCharSet) : Boolean;class operator LessThanOrEqual(a, b : WideCharSet) : Boolean;class operator GreaterThanOrEqual(a, b : WideCharSet) : Boolean;class operator NotEqual(a, b : WideCharSet) : Boolean;

Here is a more complete test of the functionality.

这是对该功能的更完整测试。

Procedure MyTest;
varNumeric : WideCharSet;WhiteSpace : WideCharSet;LowerCaseAlpha : WideCharSet;UpperCaseAlpha : WideCharSet;Alpha : WideCharSet;AlphaNumeric : WideCharSet;CommonNumericAlphaNumeric : WideCharSet;CommonUpperAndAlphaNumeric : WideCharSet;AlphaNumericMinusNumeric : WideCharSet;AlphaNumericDefinition : string;beginWhiteSpace := '[#9..#10, #13, " "]';Numeric := '["0".."9"]';LowerCaseAlpha := '["a".."z"]';UpperCaseAlpha := '["A".."Z"]';Alpha := LowerCaseAlpha + UpperCaseAlpha;AlphaNumeric := Alpha + Numeric;CommonNumericAlphaNumeric := Numeric * AlphaNumeric;CommonUpperAndAlphaNumeric := UpperCaseAlpha * AlphaNumeric;AlphaNumericMinusNumeric := AlphaNumeric - Numeric;AlphaNumericDefinition := AlphaNumeric + '["&"]';
end;

I will leave it to the reader to go over the individual methods as they are relatively common programming.

我将它留给读者阅读,因为它们是相对通用的编程方法。

One type of operation that this type of set would not be able to do (when compared to a Delphi set) is to use the functions Include and Exclude.  Those could be added as methods to the class if the functionality is desired.  This would not produce equivalent code to the set of char, but it should be familiar enough to provide the functionality well.  I will leave that as an exercise for the reader.

这种类型的集合无法进行的一种操作类型(与Delphi集合相比)是使用包含和排除功能。 如果需要功能,可以将它们作为方法添加到类中。 这不会产生与char集合等效的代码,但是应该足够熟悉才能很好地提供功能。 我将其留给读者练习。

This article should have been able to show you that using operator overloading in Delphi is not difficult, but it does have some limitations.  One is not being able to dynamically create space for member variables.  It is also limited to being used with records (one of the reasons that it cannot dynamically create space for member variables).  The help on operator overloading in Delphi mentions both that it only works with records, and that it can be used with records and classes.  I can tell you that I tried adding an operator overloading method to a class and got a compiler error.

本文应该能够向您展示,在Delphi中使用运算符重载并不困难,但确实有一些限制。 一种是不能动态地为成员变量创建空间。 它也仅限于与记录一起使用(它不能为成员变量动态创建空间的原因之一)。 Delphi中有关运算符重载的帮助提到它仅适用于记录,并且可以与记录和类一起使用。 我可以告诉你,我尝试将运算符重载方法添加到类中并遇到编译器错误。

The help on the topic in Delphi XE2 can be found using the help address:

可以使用帮助地址找到有关Delphi XE2中该主题的帮助:

ms-help://embarcadero.rs_xe2/rad/Operator_Overloading_(Delphi).html

ms-help://embarcadero.rs_x e2 / rad / Ope rator_Over loading_(D elphi.htm 升

The help states that you should not provide implicit conversions both from type A to type B and from type B to type A.  In my own code it did not present a problem, but that may be due to the fact that on of the types was a Delphi base type.

该帮助指出,您不应该同时提供从类型A到类型B以及从类型B到类型A的隐式转换。在我自己的代码中,它没有出现问题,但这可能是由于以下事实导致的: Delphi基本类型。

uWideCharSet.pas uWideCharSet.pas

翻译自: https://www.experts-exchange.com/articles/10088/An-example-of-Operator-Overloading-in-Delphi-XE2.html

delphi 操作符重载

delphi 操作符重载_Delphi XE2中的运算符重载示例相关推荐

  1. C++中的运算符重载基础

    1.C++中的运算符重载基础 所谓重载,就是赋予新的含义.函数重载(Function Overloading)可以让一个函数名有多种功能,在不同情况下进行不同的操作.运算符重载(Operator Ov ...

  2. 第十三周项目一-分数类中的运算符重载

    /**Copyright(c)2016,烟台大学计算机与控制工程学院*All rights reserved*文件名称:123.cpp*作 者:王蕊*完成日期:2016年5月25日*版 本 号:v1. ...

  3. 第十二周项目二-Time类中的运算符重载

    /**Copyright(c)2016,烟台大学计算机与控制工程学院*All rights reserved*文件名称:123.cpp*作 者:王蕊*完成日期:2016年5月24日*版 本 号:v1. ...

  4. 项目3-分数类中的运算符重载

    /* * Copyright (c) 2011, 烟台大学计算机学院 * All rights reserved. * 作 者:王静 * 完成日期:2013 年 5 月 5 日 * 版 本 号:v1. ...

  5. /项目3-分数类中的运算符重载

    /* * Copyright (c) 2011, 烟台大学计算机学院 * All rights reserved. * 作 者:王静 * 完成日期:2013 年 4 月 24 日 * 版 本 号:v1 ...

  6. 8-2 实现Time类中的运算符重载

    /* * 作 者: 霍雨佳 * 完成日期:2014 年4月15日 * 版 本 号:v1.0 * 问题描述:实现Time类中的运算符重载 * 样例输入: * 样例输出: * 项目要求:实现Time类中的 ...

  7. 实现复数类中的运算符重载(含有double类型)

    /* * 作 者: 霍雨佳 * 完成日期:2014 年4月15日 * 版 本 号:v1.0 * 问题描述:实现复数类中的运算符重载. * 样例输入: * 样例输出: * 问题分析:一个定义完整的类,是 ...

  8. 8-3 实现分数类中的运算符重载

    /* * 作 者: 霍雨佳 * 完成日期:2014 年4月15日 * 版 本 号:v1.0 * 问题描述:实现分数类中的运算符重载 * 样例输入: * 样例输出: * 项目要求:实现分数类中的运算符重 ...

  9. 第十二周上机实践项目 项目1-实现复数类中的运算符重载 (2)

    问题及代码: [项目-实现复数类中的运算符重载] (1)请用类的成员函数,定义复数类重载运算符+.-.*./,使之能用于复数的加减乘除 class Complex { public:Complex() ...

最新文章

  1. 第十一周总结CoreIDRAW
  2. Oracle技术之Data Pump介绍
  3. 从零开始学习docker(十四)Docker Compose--部署SpringCloud
  4. 关于 Google Chrome 操作系统的 5 个问题
  5. 让VS2008真正支持JQuery的智能感知
  6. java线程main异常,‘java.lang.NoSuchMethodError:main的原因’线程中的异常“main”’...
  7. mysql 1067
  8. Maple 教程(一)---初认识
  9. 解决apicloud中真机同步海马玩模拟器中每次都要升级apploader的问题
  10. 局域网文件服务器带宽,高带宽局域网
  11. 按键精灵自动过QQ滑块脚本 ,速度最快的源码库存!
  12. cmd文件闪退问题追踪办法
  13. 7-4 疯狂星期四!!!!!
  14. Python 医学知识图谱问答系统(一),建立医学知识图谱,基于neo4j知识图谱的医学问答体系
  15. 自动批量处理人像照片
  16. IBMX3650M4服务器重装window系统
  17. Spring Boot Actuator 使用介绍
  18. 不同场所最低疏散净宽度汇总
  19. stm32项目平衡车详解(stm32F407)下
  20. 7.2某地刑侦大队对涉及六个嫌疑人的一桩疑案进行分析: A、B 至少有一人作案; A、E、F 三人中至少有两人参与作案; A、D 不可能是同案犯; B、C 或同时作案,或与本案无关;

热门文章

  1. C++ 编程中常用的英文单词(首字母是A、B、C开头)
  2. 关于大数据技术的演讲_好程序员大数据培训分享大数据的两大核心技术
  3. Chrome居然是学术利器?一口气推荐15个神级插件赋能科研之路
  4. 用软件管工程合同有什么价值?
  5. 粒子群算法早熟在边界上怎么办
  6. 【非线性求解工具】pyomo初级使用手册
  7. 卡片日记 - 记录你的点滴
  8. 【java jar包 linux 部署】
  9. unix-shell-4
  10. SpringCloud ribbon源码