【问题标题】:Understanding Delphi Variable Declarations/Initializations了解 Delphi 变量声明/初始化
【发布时间】:2013-05-16 23:06:18
【问题描述】:

因为它与德尔福有关......

当一个变量被声明为某种类型时,它是否被初始化为该类型的一个 OBJECT?还是必须为变量分配一个返回该类型对象的表达式?

我来自强大的 Java 背景。我想问的是这个... 在 Java 中,假设您声明了一个名为 Orange 的用户定义类型的实例变量。看起来像这样:

private Orange _fruit;

变量 _fruit 仍然持有对 null 的引用,直到实际分配了 Orange 类的实例,如下所示:

_fruit = new Orange();

如果我在 Delphi 中声明一个 TForm 类型的变量,如下所示:

var
  Form : TForm;

Form 是否初始化为 TForm 对象?还是还是 nil?

我之所以问,是因为我在尝试编译如下所示的一小段代码时遇到错误:

这里是主要单元:

unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils,
  System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Second;

type
  TForm1 = class(TForm)
    ShowForm2: TButton;
    procedure ShowForm2Click(Sender: TObject);
  end;

var
  Form1: TForm1;
  SecondForm : TSecondForm;

implementation

{$R *.dfm}

procedure TForm1.ShowForm2Click(Sender: TObject);
begin
SecondForm.ShowModal;
end;
end.

这里是第二单元:

unit Second;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.StdCtrls;

type
  TSecondForm = class(TForm)
    Label1: TLabel;
  end;

var
  SecondForm: TSecondForm;

implementation

{$R *.dfm}

end.

我在尝试编译时遇到的错误正是:“模块 'Multiple.exe' 中地址 005B17F9 的访问冲突。读取地址 00000000。”我在想这是因为我没有以某种方式初始化单元 Main 中的变量 SecondForm?但是,我尝试在 ShowForm2Click 过程中放置​​“SecondForm.Create”,但我得到了同样的错误。我是否因为 SecondForm 未分配而收到此错误?需要初始化吗?还是这样?

注意: 我是德尔福的三天新手。请体谅。

【问题讨论】:

    标签: delphi variable-assignment variable-initialization


    【解决方案1】:

    SecondForm.Create 是错误的语法。构造函数在 Delphi 中是特殊的。您可以或多或少地将它们视为类方法。你调用它们的方式是这样的:

    variable := ClassType.Create(arguments);
    

    虽然可以像实例方法 (variable.Create) 那样调用构造函数,但这是针对特定用例的,不应在通用代码中完成。调用对象而不是类型的构造函数的原因是如果您已经在该对象的构造函数中。(即,如果您在对象上有多个构造函数并且其中一个调用另一个,或者通过使用inherited Create(arguments);调用父类上的构造函数来初始化祖先类的成员)

    您所做的,当不在该对象的另一个构造函数中时调用该对象的构造函数,如果不是错误,可能应该引发编译器警告,但不幸的是它没有。

    【讨论】:

    • 非常感谢!这是有道理的,而且有很大帮助!
    【解决方案2】:

    还要注意unit Secondunit Main 都声明了一个全局变量

    SecondForm : TSecondForm; 
    

    对于主单元,您的主单元将隐藏在unit Second 中声明的SecondForm 变量(即使它在uses 子句中列出)。对于 Delphi VCL Forms 应用程序,如果 SecondForm 是自动创建的表单,那么在 unit Second 中声明的 SecondForm 将不会是 nil,实际上已经创建了 TSecondForm 的实例并分配给它,但是unit Main 将无法访问它,因为它声明了一个同名的全局变量(与所有引用类型一样,在您对其进行操作之前,它将是 nil)。

    简而言之,最好不要在 unit Main 中声明全局 SecondForm : TSecondForm - 将其命名为其他名称,或者使用在 unit Second 中声明的全局。如果SecondForm 是自动创建表单(默认行为),那么如果您只是没有在unit Main 中重新声明SecondForm,那么上面的代码就可以工作 - 如果不是,您仍然需要实例化SecondForm

    VCL 表单是自动自动创建的表单,除非您另外指定。检查菜单:

     Project > Options > Forms
    

    查看或更改哪些表单将自动将实例分配给其 IDE 生成的全局变量。

    【讨论】:

    • 这很有意义!非常感谢!但如果我可以问一个问题只是为了确保我理解? (我也是 RAD 环境的新手。)所以当我自动创建一个新的 VCL 表单时......它不必被实例化?但是任何不是自动创建的记录、类或表单等都必须实例化吗?
    • @diosteama 如果您查看您的项目代码(在项目管理器中右键单击您的可执行文件,并查看源代码),您将看到 Delphi 生成了一些代码来实例化自动创建的表单.
    • @diosteama - 是的,基本上。当您向项目中添加新表单时,IDE 总是为表单添加一个全局实例变量并将其放入自动创建列表中。这意味着它还创建代码来实例化该全局(正如 Blorgbeard 所指出的)。如果您不希望默认全局实例化,则只需从自动创建列表中删除该表单。
    • @diosteama - 另外,为了完整,您不必实例化记录(仅类);记录在声明时分配它们需要的所有空间。如果它们是引用类型的记录,那么它们的成员需要创建实例,否则记录只是基元或指针的包,不需要任何创建。
    • 你们太棒了。非常感谢您的帮助!
    【解决方案3】:

    是的,SecondFormnil,直到您分配它。

    试试这样的:

    procedure TForm1.ShowForm2Click(Sender: TObject);
    begin
      with TSecondForm.Create(nil) do try
         ShowModal;
      finally
         Free;
      end;
    end;
    

    【讨论】:

    • +1 虽然我不得不说这是我可以容忍使用with 的唯一场景。
    • 是的,这是我使用with的唯一场景。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-26
    • 2015-12-23
    • 1970-01-01
    相关资源
    最近更新 更多