Delphi 相互依赖的程序变量和记录

Delphi 相互依赖的程序变量和记录,delphi,delphi-xe2,forward-declaration,Delphi,Delphi Xe2,Forward Declaration,我有以下结构: program Project26; {$APPTYPE CONSOLE} {$R *.res} type TPrint_address_func = function(offset: integer; info: disassembler_info): boolean; disassembler_info = record data: string; print_address_func: TPrint_address_func; end;

我有以下结构:

program Project26;

{$APPTYPE CONSOLE}
{$R *.res}
type

  TPrint_address_func = function(offset: integer; info: disassembler_info): boolean;

  disassembler_info = record
    data: string;
    print_address_func: TPrint_address_func;
  end;

begin
end.
显然,函数类型的记录需要在转发声明中声明。
,但是

是否有方法将过程变量声明为前进?

或者我可以用旧的学校对象替换记录并声明为转发吗?

您不能转发声明过程类型或记录。因此,结论是必须将类型定义放入记录中:

type
  disassembler_info = record
  type
    TPrint_address_func = function(info: disassembler_info): boolean;
  var
    data: string;
    print_address_func: TPrint_address_func;
  end;
type
  PDisassembler_info = ^TDisassembler_info;
  TPrint_address_func = function(offset: Integer;
                                 info: PDisassembler_info): Boolean;
  TDisassembler_info = record
    data: string;
    print_address_func: TPrint_address_func;
  end;
FWIW,一旦我开始在记录中定义类型,我倾向于用可见性说明符来打破声明。我会这样声明这个类型:

type
  disassembler_info = record
  public
    type
      TPrint_address_func = function(info: disassembler_info): boolean;
  public
    data: string;
    print_address_func: TPrint_address_func;
  end;
info.print_address_func(offset, info);

使用记录助手可以解决此问题

Type
  disassembler_info = record
    private
      FP: Pointer;
    public
      data: string;
  end;

  TPrint_address_func = function(info: disassembler_info): boolean;

  disassembler_info_helper = record helper for disassembler_info
  private
     procedure SetAFunc(aF: TPrint_Address_Func);
     function GetAFunc: TPrint_Address_Func;
  public
    property print_address_func: TPrint_address_func read GetAFunc write SetAFunc;
  end;

function disassembler_info_helper.GetAFunc: TPrint_Address_Func;
begin
  Result := TPrint_address_func(FP);
end;

procedure disassembler_info_helper.SetAFunc(aF: TPrint_Address_Func);
begin
  TPrint_address_func(FP) := TPrint_address_func(aF);
end;

助手使用读写方法注入
TPrint\u address\u func
属性,该方法对
反汇编程序\u info

中声明的私有变量进行操作。如果传递记录指针,则此问题很容易解决,即使在不支持嵌套记录类型的Delphi版本中也是如此。向前声明记录指针类型,然后使用记录指针声明函数类型。最后,声明记录:

type
  disassembler_info = record
  type
    TPrint_address_func = function(info: disassembler_info): boolean;
  var
    data: string;
    print_address_func: TPrint_address_func;
  end;
type
  PDisassembler_info = ^TDisassembler_info;
  TPrint_address_func = function(offset: Integer;
                                 info: PDisassembler_info): Boolean;
  TDisassembler_info = record
    data: string;
    print_address_func: TPrint_address_func;
  end;
您可能会有不止一个函数指针,而且您的记录也可能会有不止一个实例。当您扩展这个模式时,您最终将要重新发明类。考虑这一点:

type
  TDisassembler_info = class
    data: string;
    function print_address(offset: Integer): Boolean; virtual; abstract;
  end;
现在,不再定义自由函数,而是声明类的后代并重写抽象方法。随着函数指针和记录实例数量的增加,这有几个优点:

  • 编译器会自动用所有正确的值填充函数指针。它将它们存储在类的VMT中。如果您不小心忘记分配
    print\u address\u func
    ,则不会出现空函数指针。如果试图在不重写抽象方法的情况下实例化类,编译器将发出警告

  • 调用函数时不可能意外地传递错误的记录指针。在您的设计中,调用函数将如下所示:

    type
      disassembler_info = record
      public
        type
          TPrint_address_func = function(info: disassembler_info): boolean;
      public
        data: string;
        print_address_func: TPrint_address_func;
      end;
    
    info.print_address_func(offset, info);
    
    如果传递的记录参数与调用其函数的记录不同,则肯定是错误的。对于对象,冗余和出错的机会消失了:

    info.print_address(offset);
    
  • 无论有多少函数,类的单个实例的大小都保持不变,因为所有实例共享一个VMT。在当前模型中,如果记录有100个实例,那么同一个函数指针将有100个副本


  • 好的,这意味着类型定义仍将在记录外可见,对吗?@Johan是的,它是可见的,但它的名称是
    反汇编程序\u info.TPrint\u address\u func
    。这是你能做的最好的了。刚刚通过测试发现了这一点。额外的冗长令人失望,但多少可以理解。我想向前声明
    对象
    是不可能的。@Johan你可以检查一下,但我预测答案是否定的。
    对象是一种值类型,由于Delphi编译器的体系结构,您只能向前声明引用类型。您不能声明一个类型别名,
    TPrint\u address\u func\u alias=discormer\u info.TPrint\u address\u func?嗯,我很佩服他的足智多谋谢谢罗布,但我特别不想上课。不过,你提出了一个正确的观点。至于指针,它太乱了代码库。