delphi – 使用类运算符是否允许隐式类型转换?
我的记录看起来像:
TBigint = record PtrDigits: Pointer; <-- The data is somewhere else. Size: Byte; MSB: Byte; Sign: Shortint; ... class operator Implicit(a: TBigint): TBigint; <<-- is this allowed? .... 代码是类前运算符遗留代码,但我想添加运算符. 我知道数据应该存储在一个动态的byte数组中,但我不想更改代码,因为所有的东西都在x86-assembly中. 我想跟随代码触发底部的类操作符: procedure test(a: TBignum); var b: TBignum; begin b:= a; <<-- naive copy will tangle up the `PtrDigit` pointers. .... 如果我将隐式类型转换添加到自身,是否会执行以下代码? class operator TBigint.Implicit(a: TBigint): TBigint; begin sdpBigint.CreateBigint(Result,a.Size); sdpBigint.CopyBigint(a,Result); end; (如果按预期工作,将测试并添加答案). 解决方法
我的
first answer试图阻止重写赋值运算符的想法.我仍然坚持这个答案,因为很多问题都可以用对象更好地解决.
但是,David非常正确地指出TBigInt是作为利用运算符重载的记录实现的.即a:= b c;.这是坚持基于记录的实现的一个非常好的理由. 因此,我提出了这种替代解决方案,可以一石二鸟: >它消除了我在其他答案中解释的内存管理风险. (我仍然建议除非有充分的理由保留基于记录的解决方案,否则请考虑切换到基于对象的解决方案.) 总体思路如下: >定义一个表示BigInt数据的接口. (这最初可以是极简主义的,并且仅支持指针的控制 – 如我的示例所示.这将使现有代码的初始转换更容易.) 下面的代码是精简的“大型int”实现,纯粹是为了说明这些概念. (即,“大”整数仅限于常规的32位数,并且仅实现了添加.) type IBigInt = interface ['{1628BA6F-FA21-41B5-81C7-71C336B80A6B}'] function GetData: Pointer; function GetSize: Integer; procedure Realloc(ASize: Integer); function RefCount: Integer; end; type TBigIntImpl = class(TInterfacedObject,IBigInt) private FData: Pointer; FSize: Integer; protected {IBigInt} function GetData: Pointer; function GetSize: Integer; procedure Realloc(ASize: Integer); function RefCount: Integer; public constructor CreateCopy(ASource: IBigInt); destructor Destroy; override; end; type TBigInt = record PtrDigits: IBigInt; constructor CreateFromInt(AValue: Integer); class operator Implicit(AValue: TBigInt): Integer; class operator Add(AValue1,AValue2: TBigInt): TBigInt; procedure Add(AValue: Integer); strict private procedure CopyOnWriteSharedData; end; { TBigIntImpl } constructor TBigIntImpl.CreateCopy(ASource: IBigInt); begin Realloc(ASource.GetSize); Move(ASource.GetData^,FData^,FSize); end; destructor TBigIntImpl.Destroy; begin FreeMem(FData); inherited; end; function TBigIntImpl.GetData: Pointer; begin Result := FData; end; function TBigIntImpl.GetSize: Integer; begin Result := FSize; end; procedure TBigIntImpl.Realloc(ASize: Integer); begin ReallocMem(FData,ASize); FSize := ASize; end; function TBigIntImpl.RefCount: Integer; begin Result := FRefCount; end; { TBigInt } class operator TBigInt.Add(AValue1,AValue2: TBigInt): TBigInt; var LSum: Integer; begin LSum := Integer(AValue1) + Integer(AValue2); Result.CreateFromInt(LSum); end; procedure TBigInt.Add(AValue: Integer); begin CopyOnWriteSharedData; PInteger(PtrDigits.GetData)^ := PInteger(PtrDigits.GetData)^ + AValue; end; procedure TBigInt.CopyOnWriteSharedData; begin if PtrDigits.RefCount > 1 then begin PtrDigits := TBigIntImpl.CreateCopy(PtrDigits); end; end; constructor TBigInt.CreateFromInt(AValue: Integer); begin PtrDigits := TBigIntImpl.Create; PtrDigits.Realloc(SizeOf(Integer)); PInteger(PtrDigits.GetData)^ := AValue; end; class operator TBigInt.Implicit(AValue: TBigInt): Integer; begin Result := PInteger(AValue.PtrDigits.GetData)^; end; 在构建提出的解决方案时,编写了以下测试.他们证明:一些基本功能,即写时复制按预期工作,并且没有内存泄漏. procedure TTestCopyOnWrite.TestCreateFromInt; var LBigInt: TBigInt; begin LBigInt.CreateFromInt(123); CheckEquals(123,LBigInt); //Dispose(PInteger(LBigInt.PtrDigits)); //I only needed this until I //started using the interface end; procedure TTestCopyOnWrite.TestAssignment; var LValue1: TBigInt; LValue2: TBigInt; begin LValue1.CreateFromInt(123); LValue2 := LValue1; CheckEquals(123,LValue2); end; procedure TTestCopyOnWrite.TestAddMethod; var LValue1: TBigInt; begin LValue1.CreateFromInt(123); LValue1.Add(111); CheckEquals(234,LValue1); end; procedure TTestCopyOnWrite.TestOperatorAdd; var LValue1: TBigInt; LValue2: TBigInt; LActualResult: TBigInt; begin LValue1.CreateFromInt(123); LValue2.CreateFromInt(111); LActualResult := LValue1 + LValue2; CheckEquals(234,LActualResult); end; procedure TTestCopyOnWrite.TestCopyOnWrite; var LValue1: TBigInt; LValue2: TBigInt; begin LValue1.CreateFromInt(123); LValue2 := LValue1; LValue1.Add(111); { If CopyOnWrite,then LValue2 should not change } CheckEquals(234,LValue1); CheckEquals(123,LValue2); end; 编辑 添加了一个测试,证明使用TBigInt作为过程的值参数. procedure TTestCopyOnWrite.TestValueParameter; procedure CheckValueParameter(ABigInt: TBigInt); begin CheckEquals(2,ABigInt.PtrDigits.RefCount); CheckEquals(123,ABigInt); ABigInt.Add(111); CheckEquals(234,ABigInt); CheckEquals(1,ABigInt.PtrDigits.RefCount); end; var LValue: TBigInt; begin LValue.CreateFromInt(123); CheckValueParameter(LValue); end; (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |