Действительно ли Delphi обрабатывает динамические классы лучше, чем статические? - PullRequest
2 голосов
/ 10 апреля 2010

Мне не раз говорили, что 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?

Извините, у меня нет аргументов в поддержку этой гипотезы, но мне нужно мнение эксперта.

Заранее спасибо!

Ответы [ 2 ]

11 голосов
/ 10 апреля 2010

Если вы создаете класс, который содержит только переменные класса и методы класса, вы можете использовать его без создания экземпляра. То есть во втором примере вы можете использовать Tsomeclass.proc2 (но не Tsomeclass.someint, поскольку эта переменная не помечена префиксом 'class', как указал Уве).

Для (неизмеримо небольшой) разницы в скорости вы также можете пометить методы вашего класса как «статические».

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

Здесь, на мой взгляд, нет сравнения "лучше справляйся". Delphi позволяет помещать в класс «обычных» и «классных» членов. Бывший вы можете использовать только на созданном объекте, а последний вы можете использовать где угодно. Но это только две части поддержки OO в Delphi.

РЕДАКТИРОВАТЬ: Чтобы ответить на вопрос о скорости ...

Давайте составим небольшую тестовую программу:

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, компилятор подготавливает параметр (42 или $ 2A) в edx, адрес экземпляра 'tc' в eax и вызывает TTestClass.A.

Почти то же самое происходит в случае tc.B, за исключением того, что ebx разыменовывается.

В случае .A и .B eax содержит значение Self (эквивалентно C ++ для this). Когда вызывается tc.A, eax содержит адрес экземпляра 'tc'. Когда вызывается tc.B, eax содержит что-то еще (я предполагаю, что он указывает на информацию о типе для TTestClass, но я не совсем уверен в этом).

Когда код вызывает tc.C, готовится только eax, потому что «статические» методы не могут ссылаться на «Self».

Аналогичная ситуация возникает в случаях TTestClass.B / .C, за исключением того, что «Self» загружается из некоторого постоянного места, когда адрес типа TTestClass имеет тип info. хранится. В любом случае, eax содержит то же значение, когда B вызывается через экземпляр (tc.B) или через класс (TTestClass.B).

Итак, вы видите, что для статических вызовов требуется на один шаг меньше. Это было неизмеримое ускорение, к которому я обращался.

0 голосов
/ 10 апреля 2010

Вы говорите один экземпляр или нет экземпляров?

С вашим вторым примером вы не можете создать его экземпляр.

Я еще не видел, чтобы кто-нибудь использовал статические классы в рабочем коде. Вы все еще можете объявить статические (классовые) методы в вашем первом примере.

Используйте обычный типизированный класс, но объявите class var, class procedure и class function(). Вы можете вызывать методы класса и ссылаться на переменные класса, не создавая экземпляр.

Как это:

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

Обратите внимание, что переменные класса были добавлены где-то после Delphi 7, но вы определенно должны иметь возможность делать методы класса.

...