我试图找到一种优雅的方法来访问我的程序的其他部分中的某些对象的字段,方法是使用存储字节的记录并通过使用同名的函数访问另一条记录的字段作为记录的字段。
TAilmentP = Record // actually a number but acts like a pointer
private
Ordinal: Byte;
public
function Name: String; inline;
function Description: String; inline;
class operator Implicit (const Number: Byte): TAilmentP; inline;
End;
TSkill = Class
Name: String;
Power: Word;
Ailment: TAilmentP;
End;
class operator TAilmentP.Implicit (const Number: Byte): TAilmentP;
begin
Result.Ordinal := Number;
ShowMessage (IntToStr (Integer (@Result))); // for release builds
end;
function StrToAilment (const S: String): TAilmentP; // inside same unit
var i: Byte;
begin
for i := 0 to Length (Ailments) - 1 do
if Ailments [i].Name = S then
begin
ShowMessage (IntToStr (Integer (@Result))); // for release builds
Result := i; // uses the Implicit operator
Exit;
end;
raise Exception.Create ('"' + S + '" is not a valid Ailment"');
end;
现在,我试图通过重载转换运算符来使我的生活更轻松,这样当我尝试将一个字节分配给 TAilmentP 对象时,它会将其分配给 Ordinal 字段。但是,正如我检查过的,似乎这种尝试在性能方面实际上代价高昂,因为对隐式“操作员”的任何调用都会为返回值创建一个新的 TAilmentP 对象,执行其业务,然后返回值和由于地址不同,因此按字节复制回调用它的对象。
老实说,我的代码经常调用这个方法,而且这似乎比直接将我的值直接分配给我的对象的 Ordinal 字段要慢。
有没有办法让我的程序通过使用任何方法/函数将值直接分配给我的字段?即使内联似乎也不起作用。有没有办法返回对(记录)变量的引用,而不是对象本身?最后(很抱歉有点跑题了),为什么运算符重载是通过静态函数完成的?由于您可以访问对象字段而无需取消引用它们,因此使它们成为实例方法不会使其更快吗?这在这里和我的代码的其他部分真的会派上用场。
[编辑] 这是隐式运算符的汇编代码,具有所有优化且没有调试功能(甚至不是断点的“调试信息”)。
add al, [eax] /* function entry */
push ecx
mov [esp], al /* copies Byte parameter to memory */
mov eax, [esp] /* copies stored Byte back to register; function exit */
pop edx
ret
更有趣的是,下一个函数在启动时有一个 mov eax, eax 指令。现在看起来真的很有用。:P 哦,是的,我的隐式运算符也没有内联。
我非常确信 [esp] 是 Result 变量,因为它的地址与我分配的地址不同。在关闭优化的情况下,[esp] 被 [ebp-$01](我分配给的)和 [ebp-$02](字节参数)替换,再添加一条指令将 [ebp-$02] 移动到 AL(然后把它放在 [ebp-$01]) 中,冗余的 mov 指令仍然存在于 [epb-$02] 中。
我做错了什么,还是 Delphi 没有返回值优化?