Delphi真的比静态更好地处理动态类吗?

时间:2010-04-10 09:40:06

标签: delphi optimization dynamic static delphi-2009

我不止一次被告知Delphi比static更好地处理动态类。使用以下内容:

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处理?

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

提前致谢!

2 个答案:

答案 0 :(得分:11)

如果创建一个只包含类变量和类方法的类,则可以在不实例化的情况下使用它。即在你的第二个例子中你可以使用Tsomeclass.proc2(但不是Tsomeclass.someint,因为这个变量没有像Uwe指出的那样用'class'前缀标记。)

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

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。

除了取消引用ebx之外,在tc.B情况下几乎相同。

在.A和.B的情况下,eax包含'Self'的值(相当于C ++的'this')。当调用tc.A时,eax包含'tc'实例的地址。当调用tc.B时,eax包含其他东西(我猜它指的是TTestClass的类型信息,但我对此并不十分肯定)。

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

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

所以你可以看到静态调用需要一个'mov'。那是我所提到的无法估量的加速。

答案 1 :(得分:0)

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

使用第二个示例,您无法实例化它。

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

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

像这样:

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

请注意,在Delphi 7之后的某个地方添加了类变量,但你绝对应该能够使用类方法。