【问题标题】:Does Delphi really handle dynamic classes better than static?Delphi 真的比静态更好地处理动态类吗?
【发布时间】:2011-02-06 11:03:23
【问题描述】:

我不止一次被告知 Delphi 处理动态类比静态类更好。因此使用以下方法:

type Tsomeclass=class(TObject)
  private procedure proc1;
  public 
    someint:integer;
    procedure proc2;
end;

var someclass:TSomeclass;

implementation

...

initialization
  someclass:=TSomeclass.Create;
finalization
  someclass.Free;

而不是

type Tsomeclass=class
  private class procedure proc1;
  public 
    class var someint:integer;
    class procedure proc2;
end;

我正在处理的项目中 90% 的类有并且只需要一个实例。我真的必须使用第一种方式来使用这些类吗?是否更好地优化,由 Delphi 处理?

对不起,我没有论据来支持这个假设,但我想要专家的意见。

提前致谢!

【问题讨论】:

  • 您应该避免在第二个示例中访问 someint,因为它仅在该类之前实例化时才有效。也许您忘记将其标记为类变量?除此之外,向公众公开一个类字段对我来说是错误的。
  • 是的,我忘了把它设为类变量,但我已经记住了。但这里的问题不是“这是 OO”。我写了一个示例类,你说得对领域,但为什么没有人回答主要问题?
  • “我被告知”:?这些人是在什么情况下提出这种说法的?他们提供了任何证据吗?

标签: delphi optimization dynamic static delphi-2009


【解决方案1】:

如果你创建一个只包含类变量和类方法的类,那么你可以在没有实例化的情况下使用它。 IE。在您的第二个示例中,您可以使用 Tsomeclass.proc2 (但不能使用 Tsomeclass.someint,因为 Uwe 指出,此变量未标有“类”前缀)。

对于(无法测量的小)速度差异,您还可以将您的类方法标记为“静态”。

type
  TSomeclass = class
    class procedure proc2; static;
  end;

在我看来,这里没有“处理得更好”的比较。 Delphi 允许您在类中放置“普通”和“类”成员。前者只能在实例化对象上使用,后者可以在任何地方使用。但这只是 Delphi 中 OO 支持的两个部分。

编辑:回答关于速度的问题......

让我们整理一个小测试程序:

program Project61;

{$APPTYPE CONSOLE}

type
  TTestClass = class
    procedure A(a: integer);
    class procedure B(b: integer);
    class procedure C(c: integer); static;
  end;

procedure TTestClass.A(a: integer); begin end;
class procedure TTestClass.B(b: integer); begin end;
class procedure TTestClass.C(c: integer); begin end;

var
  tc: TTestClass;

begin
  tc := TTestClass.Create;
  tc.A(42);
  tc.B(42);
  tc.C(42);
  tc.Free;
  //TTestClass.A(42); // not possible
  TTestClass.B(42);
  TTestClass.C(42);
end.

启用优化的 Delphi 2010 将 .A/.B/.C 调用编译成

Project61.dpr.30: tc := TTestClass.Create;
004060C5 B201             mov dl,$01
004060C7 A154594000       mov eax,[$00405954]
004060CC E847DAFFFF       call TObject.Create
004060D1 8BD8             mov ebx,eax
Project61.dpr.31: tc.A(42);
004060D3 BA2A000000       mov edx,$0000002a
004060D8 8BC3             mov eax,ebx
004060DA E899F9FFFF       call TTestClass.A
Project61.dpr.32: tc.B(42);
004060DF BA2A000000       mov edx,$0000002a
004060E4 8B03             mov eax,[ebx]
004060E6 E891F9FFFF       call TTestClass.B
Project61.dpr.33: tc.C(42);
004060EB B82A000000       mov eax,$0000002a
004060F0 E88BF9FFFF       call TTestClass.C
Project61.dpr.34: tc.Free;
004060F5 8BC3             mov eax,ebx
004060F7 E84CDAFFFF       call TObject.Free
Project61.dpr.36: TTestClass.B(42);
004060FC BA2A000000       mov edx,$0000002a
00406101 A154594000       mov eax,[$00405954]
00406106 E871F9FFFF       call TTestClass.B
Project61.dpr.37: TTestClass.C(42);
0040610B B82A000000       mov eax,$0000002a
00406110 E86BF9FFFF       call TTestClass.C

首先创建对象,并将其地址存储到 ebx 寄存器中。

为了调用 tc.A,编译器在 edx 中准备参数(42 或 $2A),即 eax 中 'tc' 实例的地址并调用 TTestClass.A。

在 tc.B 情况下几乎相同,只是 ebx 被取消引用。

在 .A 和 .B 的情况下,eax 包含 'Self' 的值(相当于 C++ 的 'this')。当调用 tc.A 时,eax 包含 'tc' 实例的地址。当调用 tc.B 时, eax 包含其他内容(我猜它指向 TTestClass 的类型信息,但我不太确定)。

当代码调用tc.C时,只准备eax,因为'static'方法不能引用'Self'。

类似的情况发生在 TTestClass.B/.C 的情况下,除了当 TTestClass typeinfo 的地址时'Self'是从某个恒定位置加载的?被储存了。无论如何,当通过实例 (tc.B) 或通过类 (TTestClass.B) 调用 B 时,eax 包含相同的值。

因此您可以看到静态调用需要少一个“mov”。这就是我所指的不可估量的加速。

【讨论】:

  • 但是你说的是速度,我不明白。第一种方式(在我的问题中)是否比你的方式(类方法+静态且无实例)更快?
  • 另见 Delphi 简述第二章:oreilly.com/catalog/delphi/chapter/ch02.html
【解决方案2】:

你是说一个实例还是没有实例?

对于您的第二个示例,您无法实例化它。

我还没有看到有人在生产代码中使用静态类。您仍然可以在第一个示例中声明静态(类)方法。

使用常规类型类,但声明 class varclass procedureclass function()。您可以在不创建实例的情况下调用类方法并引用类变量。

像这样:

type
  TSomeClass = class(TObject)
    class var
      somevar: String;
    class procedure Hello;
  end;

请注意,类变量是在 Delphi 7 之后添加的,但您绝对应该能够执行类方法。

【讨论】:

  • 目前只有一个实例,但如果它们是静态的则没有。
  • 为什么是第一个例子?如果我不启动它,我可以使用 TsomeClass.proc1 或 TSomeClass.proc2。请您回答主要问题 - Delphi 更高效、更好地优化和更好地处理什么?
  • @John,是的。您可以在不实例化对象的情况下使用类方法和变量,就像TSomeClass.proc1()
  • 但它是否会得到更好的优化,或者我怎么说 - 比第一种方式(通过创建类的实例)更快。
  • 如果你不需要它,实例化对象会使它变慢。如果您不需要它,请不要费心创建实例。
猜你喜欢
  • 2016-12-03
  • 2011-09-27
  • 1970-01-01
  • 2011-05-01
  • 2013-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多