象棋桥 - 中国象棋论坛

首页 » 中国象棋 » 程序开发 » 太爽了,Delphi2006的record支持操作符重载了
阿摩 - 2008-1-3 21:35:00
今天查帮助的时候偶然看到, 真是不错:D 


Operator Overloading

This topic describes Delphi's operator methods and how to overload them.

About Operator Overloading
Delphi for .NET and Delphi for Win32 allow certain functions, or "operators" to be overloaded within record declarations. Delphi for .NET also allows overloading within class declarations. The name of the operator function maps to a symbolic representation in source code. For example, the Add operator maps to the + symbol. The compiler generates a call to the appropriate overload, matching the context (i.e. the return type, and type of parameters used in the call), to the signature of the operator function. The following table shows the Delphi operators that can be overloaded:
Operator Category Declaration Signature Symbol Mapping
Implicit
Conversion
Implicit(a : type) : resultType;
implicit typecast

Explicit
Conversion
Explicit(a: type) : resultType;
explicit typecast

Negative
Unary
Negative(a: type) : resultType;
-

Positive
Unary
Positive(a: type): resultType;
+

Inc
Unary
Inc(a: type) : resultType;
Inc

Dec
Unary
Dec(a: type): resultType
Dec

LogicalNot
Unary
LogicalNot(a: type): resultType;
not

BitwiseNot
Unary
BitwiseNot(a: type): resultType;
not

Trunc
Unary
Trunc(a: type): resultType;
Trunc

Round
Unary
Round(a: type): resultType;
Round

Equal
Comparison
Equal(a: type; b: type) : Boolean;
=

NotEqual
Comparison
NotEqual(a: type; b: type): Boolean;
<>

GreaterThan
Comparison
GreaterThan(a: type; b: type) Boolean;
>

GreaterThanOrEqual
Comparison
GreaterThanOrEqual(a: type; b: type): resultType;
>=

LessThan
Comparison
LessThan(a: type; b: type): resultType;
<

LessThanOrEqual
Comparison
LessThanOrEqual(a: type; b: type): resultType;
<=

Add
Binary
Add(a: type; b: type): resultType;
+

Subtract
Binary
Subtract(a: type; b: type) : resultType;
-

Multiply
Binary
Multiply(a: type; b: type) : resultType;
*

Divide
Binary
Divide(a: type; b: type) : resultType;
/

IntDivide
Binary
IntDivide(a: type; b: type): resultType;
div

Modulus
Binary
Modulus(a: type; b: type): resultType;
mod

ShiftLeft
Binary
ShiftLeft(a: type; b: type): resultType;
shl

ShiftRight
Binary
ShiftRight(a: type; b: type): resultType;
shr

LogicalAnd
Binary
LogicalAnd(a: type; b: type): resultType;
and

LogicalOr
Binary
LogicalOr(a: type; b: type): resultType;
or

LogicalXor
Binary
LogicalXor(a: type; b: type): resultType;
xor

BitwiseAnd
Binary
BitwiseAnd(a: type; b: type): resultType;
and

BitwiseOr
Binary
BitwiseOr(a: type; b: type): resultType;
or

BitwiseXor
Binary
BitwiseXor(a: type; b: type): resultType;
xor


No operators other than those listed in the table may be defined on a class or record.

Overloaded operator methods cannot be referred to by name in source code. To access a specific operator method of a specific class or record, you must use explicit typecasts on all of the operands. Operator identifiers are not included in the class or record's list of members.
No assumptions are made regarding the distributive or commutative properties of the operation. For binary operators, the first parameter is always the left operand, and the second parameter is always the right operand. Associativity is assumed to be left-to-right in the absence of explicit parentheses.
Resolution of operator methods is done over the union of accessible operators of the types used in the operation (note this includes inherited operators). For an operation involving two different types A and B, if type A has an implicit conversion to B, and B has an implicit conversion to A, an ambiguity will occur. Implicit conversions should be provided only where absolutely necessary, and reflexivity should be avoided. It is best to let type B implicitly convert itself to type A, and let type A have no knowledge of type B (or vice versa).
As a general rule, operators should not modify their operands. Instead, return a new value, constructed by performing the operation on the parameters.

Overloaded operators are used most often in records (i.e. value types). Very few classes in the .NET framework have overloaded operators, but most value types do.

Declaring Operator Overloads
Operator overloads are declared within classes or records, with the following syntax:
type
  typeName = [class | record]
      class operator conversionOp(a: type): resultType;
      class operator unaryOp(a: type): resultType;
      class operator comparisonOp(a: type; b: type): Boolean;
      class operator binaryOp(a: type; b: type): resultType;
  end;
Implementation of overloaded operators must also include the class operator syntax:
class operator typeName.conversionOp(a: type): resultType;
class operator typeName.unaryOp(a: type): resultType;
class operator typeName.comparisonOp(a: type; b: type): Boolean;
class operator typeName.binaryOp(a: type; b: type): resultType;
The following are some examples of overloaded operators:
type
  TMyClass = class
    class operator Add(a, b: TMyClass): TMyClass;      // Addition of two operands of type TMyClass
    class operator Subtract(a, b: TMyClass): TMyclass; // Subtraction of type TMyClass
    class operator Implicit(a: Integer): TMyClass;    // Implicit conversion of an Integer to type TMyClass
    class operator Implicit(a: TMyClass): Integer;    // Implicit conversion of TMyClass to Integer
    class operator Explicit(a: Double): TMyClass;      // Explicit conversion of a Double to TMyClass
  end;

// Example implementation of Add
class operator TMyClass.Add(a, b: TMyClass): TMyClass;
begin
  // ...
end;

var
x, y: TMyClass;
begin
  x := 12;      // Implicit conversion from an Integer
  y := x + x;  // Calls TMyClass.Add(a, b: TMyClass): TMyClass
  b := b + 100; // Calls TMyClass.Add(b, TMyClass.Implicit(100))
end;
阿摩 - 2008-1-3 21:38:00
日期:2005年12月13日 作者:wr960204(王锐)

虽然Delphi2006正式版还没有上市.但网络上已经有流露出来的版本.下载试用了一下
Delphi8和Delphi2005 for .NET早就实现了操作符重载.
现在新的Delphi2006中Win32部分的记录也支持操作符重载了.
根据Delphi2006的帮助说记录已经可以支持方法和属性了.
为了有别于类,
1.记录不可以继承.没有继承protected成员就没有意义了.所以记录只有Private和Public两种封装方式.
2.记录可以是变体型记录.类不行.
3.记录是职类型,而类是引用类型(引用和指针的混合体)
4.记录可以操作符重载.而类只有在Delphi.NET中才能实现操作符重载
5.记录构造器必须有一个或多个参数.
6,记录没有析构器
7,因为没有继承所以记录也不能有虚方法/动态方法.
8.Delphi Win32记录不能绑定接口.当然Delphi.NET可以


记录支持上面的先进功能以后对以前的代码几乎没有影响.首先和类一样,记录的方法不占用实例的存储空间,记录不支持虚方法/动态方法,也就没有VMT/DMT所占的空间.所以记录在内存中的存储方式和以前版本的没有方法的记录完全一样.属性其实就是读和写的方法也是不占用实例存储空间的.

上面扩展的功能里面最让我激动的就是Win32部分地记录也支持操作符重载了.
那样的话我们可以建立自己的字符串类型记录,可以是现"+",":="等等的重载.也可以实现矩阵记录.很轻松就能实现矩阵的乘法等计算.(记得Danny的博客上说以后要让Delphi支持各种几何和数学函数库.估计让记录支持操作符重载就是打的伏笔)


于是我无聊之中实现了一个字符串扩展TStrEx来体验了一下Delphi2006的记录操作符重载.

怎一个爽字了得!!哈哈


使用方式如下:

var
  K:TStrEx;
begin
  K :='  ?';
  K := K + '的长度是 %d';   //和字符串相加
  K := K.Trim();        //去掉空格
  K[1] := 'K';
  K := K.Format([K.Length]);  //格式化
  ShowMessage(K);       //显示

end;

很爽吧.以前的Delphi程序员看了一定会叫起来.TStrEx到底是简单的字符串类型还是类啊.呵呵
TStrEx的实现代码如下.

{

  Delphi2006操作符重载体验.爽!
         By wr960204(王锐) 2005/12/12
}

unit StringExUtils;

interface
uses
  SysUtils;

Type
  {增强字符串}
  TStrEx =record
  private
   FBuf:String;
   procedure SetLength(const Value: Cardinal);
   function GetLength: Cardinal;
   function GetChar(Index: Integer): char;
   procedure SetChar(Index: Integer; const Value: char);

  public
   {重载操作符}
   class operator Implicit(Str: String): TStrEx;// 重载 :=
   class operator Implicit(Str: TStrEx): String;// 重载 :=
   class operator Add(Str1,Str2:TStrEx): TStrEx;// 重载 +
   class operator Add(Str1:String;Str2:TStrEx): TStrEx;// 重载 +
   class operator Add(Str1:TStrEx;Str2:String): TStrEx;// 重载 +
   class operator Explicit(Str: TStrEx): Pointer; // 重载强制转换Pointer()
   class operator Explicit(Str: TStrEx): PChar;  // 重载强制转换PChar()
   class operator Explicit(Str: TStrEx): String; // 重载强制转换String()
   {公有方法}
   Function ToUpperCase():TStrEx;overload;              // 大写
   Function ToUpperCase(StartIndex,ALen:Integer):TStrEx;overload;  // 部分大写
   Function ToLowerCase():TStrEx;overload;              // 小写
   Function ToLowerCase(StartIndex,ALen:Integer):TStrEx;overload;  // 部分小写

   Function MdiStr(StartIndex,ALen:Integer):TStrEx;  //取子字符串
   Function LeftStr(ALen:Integer):TStrEx;             //左边子字符串
   Function RightStr(ALen:Integer):TStrEx;             //右边子字符串

   Function Insert(Index:Integer; Str:TStrEx):TStrEx; //插入
   Function Delete(StartIndex,ALen:Integer):TStrEx;  //去掉
   Function Append(Str:TStrEx):TStrEx;

   Function Trim():TStrEx;       //去掉两边空格
   Function TrimLeft():TStrEx;     //去掉左边空格
   Function TrimRight():TStrEx;     //去掉右边空格

   Function Pos(SubStr:TStrEx):Integer; //定位
   Function Replace(FromStr,ToStr:TStrEx):TStrEx;overload; //替换
   Function Replace(FromStr,ToStr:TStrEx;Flags: TReplaceFlags):TStrEx;overload; //替换

   Function Format(const Args: array of const):TStrEx;   //格式化
   Function Fill(C:Char):TStrEx;      //填充字符
   {属性}
   property Chars[Index:Integer]:Char read GetChar write SetChar; default;
   property Length:Cardinal read GetLength write SetLength;



  end;

implementation

{ TStringEx }

class operator TStrEx.Add(Str1, Str2: TStrEx): TStrEx;
begin
  Result.FBuf := Str1.FBuf + Str2.FBuf;
end;

class operator TStrEx.Add(Str1: String; Str2: TStrEx): TStrEx;
begin
  Result.FBuf := Str1 + Str2.FBuf;
end;

class operator TStrEx.Add(Str1: TStrEx; Str2: String): TStrEx;
begin
  Result.FBuf := Str1.FBuf + Str2;
end;

function TStrEx.Append(Str: TStrEx): TStrEx;
begin
  Result.FBuf := Self.FBuf + Str.FBuf;
end;

function TStrEx.Delete(StartIndex, ALen: Integer): TStrEx;
var
  I:Integer;
begin
  Result.Length := Self.Length - ALen;
  for I:= 1 to Self.Length do
  begin
  if I < StartIndex then
  begin
  Result.FBuf[i] := Self.Fbuf[i];
  end
  else
  if (I >=StartIndex + ALen) then
  begin
  Result.FBuf[I - ALen] := Self.Fbuf[i];
  end;
  
  end;
end;

class operator TStrEx.Explicit(Str: TStrEx): Pointer;
begin
  Result := PChar(Str.Fbuf);
end;

class operator TStrEx.Explicit(Str: TStrEx): PChar;
begin
  Result := PChar(Str.Fbuf);
end;

class operator TStrEx.Explicit(Str: TStrEx): String;
begin
  Result := Str.FBuf;
end;

function TStrEx.Fill(C: Char): TStrEx;
begin
  Result.Length := Self.Length;
  if Result.Length = 0 then
  Exit;
  System.FillChar(Result.FBuf[1],Result.Length,C);
end;

function TStrEx.Format(const Args: array of const): TStrEx;
begin
  Result.FBuf := SysUtils.Format(Self.FBuf,Args);
end;

function TStrEx.GetChar(Index: Integer): char;
begin
  Result := FBuf[Index];
end;

function TStrEx.GetLength: Cardinal;
begin
  Result := System.Length(FBuf);
end;

class operator TStrEx.Implicit(Str: String): TStrEx;
begin
  Result.FBuf := Str;
end;

class operator TStrEx.Implicit(Str: TStrEx): String;
begin
  Result := Str.FBuf;
end;

function TStrEx.Insert(Index: Integer; Str: TStrEx): TStrEx;
var
  I:Integer;
begin
  Result.Length := Self.Length + Str.Length;
  for I := 1 to Result.Length do
  begin
  if I < Index then
  begin
  Result.FBuf[i] := Self.FBuf[i];
  end
  else
  if (I >=Index)and(I<Index + Str.Length) then
  begin
  Result.FBuf[i] := Str.FBuf[I - Index+1];
  end
  else
  if I>=Index + Str.Length then
  begin
  Result.FBuf[i] := Self.FBuf[I - Str.Length];
  end;
  end;

end;

procedure TStrEx.SetChar(Index: Integer; const Value: char);
begin
  FBuf[Index] := Value;
end;

procedure TStrEx.SetLength(const Value: Cardinal);
begin
  System.SetLength(FBuf,Value);
end;

function TStrEx.LeftStr(ALen: Integer): TStrEx;
begin
  Result := MdiStr(1,ALen);
end;

function TStrEx.Pos(SubStr: TStrEx): Integer;
begin
  Result := System.Pos(SubStr.FBuf, Self.FBuf);
end;

function TStrEx.Replace(FromStr, ToStr: TStrEx): TStrEx;
begin
  Result := Replace(FromStr, ToStr, [rfReplaceAll]);
end;

function TStrEx.Replace(FromStr, ToStr: TStrEx; Flags: TReplaceFlags): TStrEx;
begin
  Result.FBuf := SysUtils.StringReplace(Self.FBuf,FromStr,ToStr,Flags);
end;

function TStrEx.RightStr(ALen: Integer): TStrEx;
begin
  Result := MdiStr(Self.Length-ALen + 1,ALen);
end;

function TStrEx.MdiStr(StartIndex, ALen: Integer): TStrEx;
begin
  Result := Copy(FBuf,StartIndex, ALen);
end;

function TStrEx.ToLowerCase: TStrEx;
begin
  Result := ToLowerCase(1,Length);
end;

function TStrEx.ToLowerCase(StartIndex, ALen: Integer): TStrEx;
var
  I:Integer;
begin
  Result.FBuf := Self.FBuf;
  for I := StartIndex to StartIndex + ALen do
  begin
  if I > Length then
  Exit;
  if Result.FBuf[i] in ['A'..'Z'] then
  begin
  Result.FBuf[i] := Char(Ord(Result.FBuf[i])+32);
  end;
  end;
end;

function TStrEx.ToUpperCase: TStrEx;
begin
  Result := ToUpperCase(1, Length);
end;

function TStrEx.ToUpperCase(StartIndex, ALen: Integer): TStrEx;
var
  I:Integer;
begin
  Result.FBuf := Self.FBuf;
  for I := StartIndex to StartIndex + ALen do
  begin
  if I > Length then
  Exit;
  if Result.FBuf[i] in ['a'..'z'] then
  begin
  Result.FBuf[i] := Char(Ord(Result.FBuf[i])-32);
  end;
  end;
end;

function TStrEx.Trim: TStrEx;
begin
  Result.FBuf := SysUtils.Trim(Self.FBuf);
end;

function TStrEx.TrimLeft: TStrEx;
begin
  Result.FBuf := SysUtils.TrimLeft(Self.FBuf);
end;

function TStrEx.TrimRight: TStrEx;
begin
  Result.FBuf := SysUtils.TrimRight(Self.FBuf);
end;

end.


阿摩 - 2008-1-3 21:39:00
看来N年不用Delphi, Delphi进步很多, 自己落伍太多了
阿摩 - 2008-3-15 10:54:00
Delphi2006把内存管理器也换掉了,现在这个比原先那个好多了
msnmgqsyh - 2008-3-25 22:29:00
呵呵,太专业了,感谢分享!
1
查看完整版本: 太爽了,Delphi2006的record支持操作符重载了