【问题标题】:Pointer to Function of (Sub-)Method?指向(子)方法函数的指针?
【发布时间】:2014-07-21 13:10:04
【问题描述】:

如果你喜欢使用方法的指针作为参数,你需要将方法type 设置为function of object 这样工作好:

type TAcceptor = function(filename:string):boolean of object;
function acceptor(filename:string):boolean; 
begin 
  result := filename <> ''; 
end;

如果你喜欢使用子方法的指针怎么办?它不起作用:

procedure TForm1.Button1Click(Sender:TObject);
  function acceptor(filename:string):boolean of object;
  begin 
    result := filename <> ''; 
  end;
begin
end;

发生错误:; expected but OF found!

问题:有没有子函数指针?可以投吗?

【问题讨论】:

  • 您问题中的代码无法编译。您不能在函数定义中写入对象。
  • @DavidHeffernan 你是对的,我更新了代码。
  • 肯定报错是因为语法错误;代码示例与提出的问题无关,或者我不明白实际提出的问题。
  • @user246408 David 不是指 2.snipplet,他提到了 1.snipplet,我写的第一个 snipplet works good 是无效的。检查编辑历史以了解 1.snipplet 不起作用的原因。 David 确实很好理解 2.snipplet 仅用于了解我尝试做什么,并且他明白 2.snipplet 从未声称可编译。

标签: delphi pointers delphi-7


【解决方案1】:

我不明白这怎么可能。

http://docwiki.embarcadero.com/RADStudio/XE6/en/Procedural_Types

如果您查看method pointers 部分,它明确表示不能使用嵌套过程和函数:

"嵌套过程和函数(在其他程序中声明的例程 例程)不能用作程序值,也不能预定义 过程和功能。”

您也许可以使用匿名方法来解决它。比如:

procedure TForm1.Button1Click(Sender:TObject);
begin
  DoSomethingWithAcceptor(function(FileName: string): Boolean
  begin 
    Result := FileName <> '';
  end);
end;

【讨论】:

  • +1 这是正确的。碰巧的是,x86 下不使用包含参数/变量的嵌套函数可以成功获取其地址。但正如文档所说,这样做是错误的。当代码在 x64 下编译时,鸡就回家了。
  • 为了兼容性,我仅限于 Delphi7,太糟糕了。无论如何,您的答案看起来是正确的。我想我会照原样使用第一行。
  • 有一种方法可以模仿这一点(使用嵌套的过程)。我以前做过,在 Turbo Vision 中是作为一种“穷人的匿名方法”来做的。如果我能找到它,我会尝试发布我的代码。
  • @Rudy 对嵌套函数的任何此类使用都依赖于实现细节,并且对于更改该细节的编译器来说并不健壮,正如之前已经多次讨论过的那样。
  • 正如我所说,自 Delphi 2 以来它没有改变,因此在许多版本中它一直保持不变。问题是关于 Delphi 7,它是一个特定版本。这个细节可能会改变吗?
【解决方案2】:

注意

我知道以下内容并不普遍适用,但它适用于所有已知的 Win32 版本的 Delphi。只要您意识到这一点,并在新版本中检查它的功能,它就是一个可行的 hack,IMO。


将嵌套函数传递给方法

在旧代码中,我用它来做一些“穷人的匿名方法”:

type
  TLocal = packed record
    Code: Pointer;  // local (nested) function
    Frame: Pointer; // outer stack frame for local function
   end;

为了在方法内部填充这样的局部,我编写了函数 Local:

function Local(LocalFunction: Pointer): TLocal;
asm
  MOV [EDX].TLocal.Frame,EBP
  MOV [EDX].TLocal.Code,EAX
end;

在我的单元(某种通用集合)中,我编写了一个函数来调用它们,传递一个参数(在这种情况下,类型为 TGeneric,在这种情况下,这并不重要,你也可以传递一个指针或类似的东西) .

// Calls local function using local closure provided, passing
// T as parameter to the local.
function CallLocal(T: TGeneric; const Local: TLocal): TGeneric;
asm 
  PUSH [EDX].TLocal.Frame
  CALL [EDX].TLocal.Code
  ADD ESP,4
end;

它是这样使用的:

function TStdCollection.AsArray: TGenericArray;
var
  I: Integer;
  A: TGenericArray;

  procedure ToArray(E: TGeneric);
  begin
    Result[I] := E.Traits.Copy(E);
    Inc(I);
  end;

begin
  SetLength(A, Count);
  I := 0;
  ForEach(Local(@ToArray));
  Assert(I = Count);
  Result := A;
end;

嵌套函数中的代码复制元素并将其存储在数组中。然后,主过程将嵌套函数 ToArray(连同其堆栈帧)作为参数传递给 ForEach,其实现方式如下:

function TStdCollection.ForEach(Operation: TLocal): ICollection;
var
  Enum: IEnumerator;
  Elem: TGeneric;
begin
  Enum := GetEnumerator;
  Elem := Enum.First;
  while Elem <> nil do
  begin
    CallLocal(Elem, Operation);
    Elem := Enum.Next;
  end;
  Result := Self;
end;

这些示例展示了如何使用 Locals。我希望这或多或少能回答你的问题。

注意

请注意,此代码是在 Delphi 6 时间范围内编写的。我知道现在有更好的选择,比如泛型和匿名方法。但是如果需要与 Delphi 7 兼容,上面可能是一个解决方案。

【讨论】:

  • 有效,但不适用于 Kylix。
  • 不,不适合 Kylix。我已经提到过Win32。顺便说一句,我不知道还有人在使用 Kylix。
  • 我是恐龙 - roarrrrr
猜你喜欢
  • 1970-01-01
  • 2017-04-13
  • 2019-01-08
  • 1970-01-01
  • 1970-01-01
  • 2015-04-18
  • 1970-01-01
  • 1970-01-01
  • 2011-04-26
相关资源
最近更新 更多