Константы Класса / Статические Константы в Delphi

Эта строка вызывает вашу ошибку:

return ((lhs.numerator() * rhs.denominator()) + (lhs.denominator() * rhs.numerator()), lhs.denominator() * rhs.denominator());

Проблема в том, что она оценивается как целое, что дает вам целое число. Это целое число затем передается неявно вызванному конструктору вашего класса Rational. Обратите внимание, что в этой строке используется запятая. Для кода, подобного a, b, он сначала оценивает a, отбрасывает результат, а затем оценивает b и сохраняет этот результат как результат общего выражения. Это не то, что вы хотели.

15
задан MB. 16 September 2008 в 12:38
поделиться

9 ответов

Вот то, как я сделаю то использование переменной класса, процедуры класса и блока инициализации:

unit MyObject;

interface

type

TMyObject = class
   private
     class var FLogger : TLogLogger;
   public
     class procedure SetLogger(value:TLogLogger);
     class procedure FreeLogger;
   end;

implementation

class procedure TMyObject.SetLogger(value:TLogLogger);
begin
  // sanity checks here
  FLogger := Value;
end;

class procedure TMyObject.FreeLogger;
begin
  if assigned(FLogger) then 
    FLogger.Free;
end;

initialization
  TMyObject.SetLogger(TLogLogger.Create);
finalization
  TMyObject.FreeLogger;
end.
16
ответ дан 1 December 2019 в 02:10
поделиться

Перед версией 7 Delphi не имел статических переменных, необходимо будет использовать глобальную переменную.

Для создания его максимально частным поместите его в implementation раздел единицы.

0
ответ дан 1 December 2019 в 02:10
поделиться
 TMyObject = class
    private
      class var FLogger : TLogLogger;
      procedure SetLogger(value:TLogLogger);
      property Logger : TLogLogger read FLogger write SetLogger;
    end;

procedure TMyObject.SetLogger(value:TLogLogger);
begin
  // sanity checks here
  FLogger := Value;
end;

Примечание, что эта переменная класса будет перезаписываема от любого экземпляра класса, следовательно можно настроить его где-то в другом месте в коде, обычно на основе некоторого условия (тип регистратора и т.д.).

Редактирование: Это также будет то же во всех потомках класса. Измените его в одном из детей, и это изменяется для всех порожденных экземпляров. Вы могли также настроить обработку экземпляра по умолчанию.

 TMyObject = class
    private
      class var FLogger : TLogLogger;
      procedure SetLogger(value:TLogLogger);
      function GetLogger:TLogLogger;
      property Logger : TLogLogger read GetLogger write SetLogger;
    end;

function TMyObject.GetLogger:TLogLogger;
begin
  if not Assigned(FLogger)
   then FLogger := TSomeLogLoggerClass.Create;
  Result := FLogger;
end;

procedure TMyObject.SetLogger(value:TLogLogger);
begin
  // sanity checks here
  FLogger := Value;
end;
4
ответ дан 1 December 2019 в 02:10
поделиться

В прошлом году Hallvard Vassbotn вел блог о взломе Delphi, который я сделал для этого, это стало статьей с двумя частями:

  1. Hack#17: Виртуальные переменные класса, Первая часть
  2. Hack#17: Виртуальные переменные класса, Вторая часть

Да, это - долгое чтение, но очень полезный.

, Таким образом, я снова использовал запись VMT (устаревшую), названную vmtAutoTable как переменная. Этот слот в VMT может использоваться для хранения любого 4-байтового значения, но если Вы хотите сохранить, Вы могли бы всегда выделять запись со всеми полями, которых Вы могли пожелать.

4
ответ дан 1 December 2019 в 02:10
поделиться

Ключевые слова, которые Вы ищете, являются "var класса" - это запускает блок переменных класса в Вашем объявлении класса. Необходимо закончить блок "var", если Вы хотите включать другие поля после него (иначе, блок может быть закончен "частным", "общедоступным", "процедура" и т.д. спецификатор). Например,

(Редактирование: Я перечитал вопрос и переместил подсчет ссылок в TMyClass - поскольку Вы не можете редактировать класс TMySharedObjectClass, который Вы хотите совместно использовать, если он прибывает из чужой библиотеки)

  TMyClass = class(TObject)
  strict private
    class var
      FMySharedObjectRefCount: integer;
      FMySharedObject: TMySharedObjectClass;
    var
    FOtherNonClassField1: integer;
    function GetMySharedObject: TMySharedObjectClass;
  public
    constructor Create;
    destructor Destroy; override;
    property MySharedObject: TMySharedObjectClass read GetMySharedObject;
  end;


{ TMyClass }
constructor TMyClass.Create;
begin
  if not Assigned(FMySharedObject) then
    FMySharedObject := TMySharedObjectClass.Create;
  Inc(FMySharedObjectRefCount);
end;

destructor TMyClass.Destroy;
begin
  Dec(FMySharedObjectRefCount);
  if (FMySharedObjectRefCount < 1) then
    FreeAndNil(FMySharedObject);

  inherited;
end;

function TMyClass.GetMySharedObject: TMySharedObjectClass;
begin
  Result := FMySharedObject;
end;

, обратите внимание, что вышеупомянутое не ориентировано на многопотоковое исполнение, и могут быть лучшие способы подсчета ссылок (такие как использование Интерфейсов), но это - простой пример, который должен запустить Вас. Обратите внимание, что TMySharedObjectClass может быть заменен TLogLogger или независимо от того, что Вам нравится.

2
ответ дан 1 December 2019 в 02:10
поделиться

Поскольку, что я хочу сделать (частный постоянный класс), самое опрятное решение, которое я могу предложить (на основе ответов до сих пор):

unit MyObject;

interface

type

TMyObject = class
private
  class var FLogger: TLogLogger;
end;

implementation

initialization
  TMyObject.FLogger:= TLogLogger.GetLogger(TMyObject);
finalization
  // You'd typically want to free the class objects in the finalization block, but
  // TLogLoggers are actually managed by Log4D.

end.

, Возможно, немного более объектно-ориентированный было бы что-то как:

unit MyObject;

interface

type

TMyObject = class
strict private
  class var FLogger: TLogLogger;
private
  class procedure InitClass;
  class procedure FreeClass;
end;

implementation

class procedure TMyObject.InitClass;
begin
  FLogger:= TLogLogger.GetLogger(TMyObject);
end;

class procedure TMyObject.FreeClass;
begin
  // Nothing to do here for a TLogLogger - it's freed by Log4D.
end;

initialization
  TMyObject.InitClass;
finalization
  TMyObject.FreeClass;

end.

, Который мог бы иметь больше смысла, если бы было несколько таких констант класса.

1
ответ дан 1 December 2019 в 02:10
поделиться

В Delphi статические переменные реализованы как константы тип переменных :)

Это могло быть несколько вводящим в заблуждение.

procedure TForm1.Button1Click(Sender: TObject) ;
const
   clicks : Integer = 1; //not a true constant
begin
  Form1.Caption := IntToStr(clicks) ;
  clicks := clicks + 1;
end;

И да, другая возможность использует глобальную переменную в implementation часть Вашего модуля.

Это только работает, если переключатель компилятора "Присваиваемый Consts" включен, глобально или с {$J+} синтаксис (tnx Lars).

0
ответ дан 1 December 2019 в 02:10
поделиться

Два вопроса я думаю, что должен быть отвечен перед предложением "идеального" решения..

  • первое, ориентирован ли TLogLogger на многопотоковое исполнение. Тот же TLogLogger можно назвать от нескольких потоков без вызовы к "syncronize"? Даже если так, в следующем мае все еще подайте заявку
  • , поток в объеме переменных класса или действительно глобальный?
  • , Если переменные класса действительно глобальны, и TLogLogger, не ориентировано на многопотоковое исполнение, Вы могли бы быть лучшими для использования глобального единицей threadvar для хранения TLogLogger (так же, поскольку мне не нравится использовать "глобальный" Вар в любой форме), например,

Код:

interface
type
  TMyObject = class(TObject)
  private
    FLogger: TLogLogger; //NB: pointer to shared threadvar
  public
    constructor Create;
  end;
implementation
threadvar threadGlobalLogger: TLogLogger = nil;
constructor TMyObject.Create;
begin
  if not Assigned(threadGlobalLogger) then
    threadGlobalLogger := TLogLogger.GetLogger(TMyObject); //NB: No need to reference count or explicitly free, as it's freed by Log4D
  FLogger := threadGlobalLogger;
end;

Редактирование: кажется, что переменные класса глобально хранятся, а не экземпляр на поток. См. этот вопрос для деталей.

1
ответ дан 1 December 2019 в 02:10
поделиться

Ну, это не красиво, но отлично работает в Delphi 7:

TMyObject = class
pulic
    class function MySharedObject: TMySharedObject; // I'm lazy so it will be read only
end;

implementation

...

class function MySharedObject: TMySharedObject;
{$J+} const MySharedObjectInstance: TMySharedObject = nil; {$J-} // {$J+} Makes the consts writable
begin
    // any conditional initialization ...
   if (not Assigned(MySharedObjectInstance)) then
       MySharedObjectInstance = TMySharedOject.Create(...);
  Result := MySharedObjectInstance;
end;

Я сейчас использую его для создания одиночных объектов.

2
ответ дан 1 December 2019 в 02:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: